// source --> https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/gmap3.js?ver=5.1.1 /*! * GMAP3 Plugin for JQuery * Version : 5.1.1 * Date : 2013-05-25 * Licence : GPL v3 : http://www.gnu.org/licenses/gpl.html * Author : DEMONTE Jean-Baptiste * Contact : jbdemonte@gmail.com * Web site : http://gmap3.net * * Copyright (c) 2010-2012 Jean-Baptiste DEMONTE * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * - Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ ;(function ($, undef) { /***************************************************************************/ /* GMAP3 DEFAULTS */ /***************************************************************************/ // defaults are defined later in the code to pass the rails asset pipeline and //jasmine while google library is not loaded var defaults, gId = 0; function initDefaults() { if (!defaults) { defaults = { verbose: false, queryLimit: { attempt: 5, delay: 250, // setTimeout(..., delay + random); random: 250 }, classes: { Map : google.maps.Map, Marker : google.maps.Marker, InfoWindow : google.maps.InfoWindow, Circle : google.maps.Circle, Rectangle : google.maps.Rectangle, OverlayView : google.maps.OverlayView, StreetViewPanorama: google.maps.StreetViewPanorama, KmlLayer : google.maps.KmlLayer, TrafficLayer : google.maps.TrafficLayer, BicyclingLayer : google.maps.BicyclingLayer, GroundOverlay : google.maps.GroundOverlay, StyledMapType : google.maps.StyledMapType, ImageMapType : google.maps.ImageMapType }, map: { mapTypeId : google.maps.MapTypeId.ROADMAP, center: [46.578498, 2.457275], zoom: 2 }, overlay: { pane: "floatPane", content: "", offset: { x: 0, y: 0 } }, geoloc: { getCurrentPosition: { maximumAge: 60000, timeout: 5000 } } } } } function globalId(id, simulate){ return id !== undef ? id : "gmap3_" + (simulate ? gId + 1 : ++gId); } /** * Return true if current version of Google Maps is equal or above to these in parameter * @param version {string} Minimal version required * @return {Boolean} */ function googleVersionMin(version) { var i, gmVersion = google.maps.version.split("."); version = version.split("."); for(i = 0; i < gmVersion.length; i++) { gmVersion[i] = parseInt(gmVersion[i], 10); } for(i = 0; i < version.length; i++) { version[i] = parseInt(version[i], 10); if (gmVersion.hasOwnProperty(i)) { if (gmVersion[i] < version[i]) { return false; } } else { return false; } } return true; } /** * attach events from a container to a sender * todo[ * events => { eventName => function, } * onces => { eventName => function, } * data => mixed data * ] **/ function attachEvents($container, args, sender, id, senders){ if (args.todo.events || args.todo.onces) { var context = { id: id, data: args.todo.data, tag: args.todo.tag }; if (args.todo.events){ $.each(args.todo.events, function(name, f){ var that = $container, fn = f; if ($.isArray(f)) { that = f[0]; fn = f[1] } google.maps.event.addListener(sender, name, function(event) { fn.apply(that, [senders ? senders : sender, event, context]); }); }); } if (args.todo.onces){ $.each(args.todo.onces, function(name, f){ var that = $container, fn = f; if ($.isArray(f)) { that = f[0]; fn = f[1] } google.maps.event.addListenerOnce(sender, name, function(event) { fn.apply(that, [senders ? senders : sender, event, context]); }); }); } } } /***************************************************************************/ /* STACK */ /***************************************************************************/ function Stack (){ var st = []; this.empty = function (){ return !st.length; }; this.add = function(v){ st.push(v); }; this.get = function (){ return st.length ? st[0] : false; }; this.ack = function (){ st.shift(); }; } /***************************************************************************/ /* TASK */ /***************************************************************************/ function Task(ctx, onEnd, todo){ var session = {}, that = this, current, resolve = { latLng:{ // function => bool (=> address = latLng) map:false, marker:false, infowindow:false, circle:false, overlay: false, getlatlng: false, getmaxzoom: false, getelevation: false, streetviewpanorama: false, getaddress: true }, geoloc:{ getgeoloc: true } }; if (typeof todo === "string"){ todo = unify(todo); } function unify(todo){ var result = {}; result[todo] = {}; return result; } function next(){ var k; for(k in todo){ if (k in session){ // already run continue; } return k; } } this.run = function (){ var k, opts; while(k = next()){ if (typeof ctx[k] === "function"){ current = k; opts = $.extend(true, {}, defaults[k] || {}, todo[k].options || {}); if (k in resolve.latLng){ if (todo[k].values){ resolveAllLatLng(todo[k].values, ctx, ctx[k], {todo:todo[k], opts:opts, session:session}); } else { resolveLatLng(ctx, ctx[k], resolve.latLng[k], {todo:todo[k], opts:opts, session:session}); } } else if (k in resolve.geoloc){ geoloc(ctx, ctx[k], {todo:todo[k], opts:opts, session:session}); } else { ctx[k].apply(ctx, [{todo:todo[k], opts:opts, session:session}]); } return; // wait until ack } else { session[k] = null; } } onEnd.apply(ctx, [todo, session]); }; this.ack = function(result){ session[current] = result; that.run.apply(that, []); }; } function getKeys(obj){ var k, keys = []; for(k in obj){ keys.push(k); } return keys; } function tuple(args, value){ var todo = {}; // "copy" the common data if (args.todo){ for(var k in args.todo){ if ((k !== "options") && (k !== "values")){ todo[k] = args.todo[k]; } } } // "copy" some specific keys from value first else args.todo var i, keys = ["data", "tag", "id", "events", "onces"]; for(i=0; i done in a function, to let dead-code analyser works without google library loaded **/ function newEmptyOverlay(map, radius){ function Overlay(){ this.onAdd = function(){}; this.onRemove = function(){}; this.draw = function(){}; return defaults.classes.OverlayView.apply(this, []); } Overlay.prototype = defaults.classes.OverlayView.prototype; var obj = new Overlay(); obj.setMap(map); return obj; } /** * Class InternalClusterer * This class manage clusters thanks to "todo" objects * * Note: * Individuals marker are created on the fly thanks to the todo objects, they are * first set to null to keep the indexes synchronised with the todo list * This is the "display" function, set by the gmap3 object, which uses theses data * to create markers when clusters are not required * To remove a marker, the objects are deleted and set not null in arrays * markers[key] * = null : marker exist but has not been displayed yet * = false : marker has been removed **/ function InternalClusterer($container, map, raw){ var updating = false, updated = false, redrawing = false, ready = false, enabled = true, that = this, events = [], store = {}, // combin of index (id1-id2-...) => object ids = {}, // unique id => index idxs = {}, // index => unique id markers = [], // index => marker todos = [], // index => todo or null if removed values = [], // index => value overlay = newEmptyOverlay(map, raw.radius), timer, projection, ffilter, fdisplay, ferror; // callback function main(); function prepareMarker(index) { if (!markers[index]) { delete todos[index].options.map; markers[index] = new defaults.classes.Marker(todos[index].options); attachEvents($container, {todo: todos[index]}, markers[index], todos[index].id); } } /** * return a marker by its id, null if not yet displayed and false if no exist or removed **/ this.getById = function(id){ if (id in ids) { prepareMarker(ids[id]); return markers[ids[id]]; } return false; }; /** * remove one object from the store **/ this.rm = function (id) { var index = ids[id]; if (markers[index]){ // can be null markers[index].setMap(null); } delete markers[index]; markers[index] = false; delete todos[index]; todos[index] = false; delete values[index]; values[index] = false; delete ids[id]; delete idxs[index]; updated = true; }; /** * remove a marker by its id **/ this.clearById = function(id){ if (id in ids){ this.rm(id); return true; } }; /** * remove objects from the store **/ this.clear = function(last, first, tag){ var start, stop, step, index, i, list = [], check = ftag(tag); if (last) { start = todos.length - 1; stop = -1; step = -1; } else { start = 0; stop = todos.length; step = 1; } for (index = start; index != stop; index += step) { if (todos[index]) { if (!check || check(todos[index].tag)){ list.push(idxs[index]); if (first || last) { break; } } } } for (i = 0; i < list.length; i++) { this.rm(list[i]); } }; // add a "marker todo" to the cluster this.add = function(todo, value){ todo.id = globalId(todo.id); this.clearById(todo.id); ids[todo.id] = markers.length; idxs[markers.length] = todo.id; markers.push(null); // null = marker not yet created / displayed todos.push(todo); values.push(value); updated = true; }; // add a real marker to the cluster this.addMarker = function(marker, todo){ todo = todo || {}; todo.id = globalId(todo.id); this.clearById(todo.id); if (!todo.options){ todo.options = {}; } todo.options.position = marker.getPosition(); attachEvents($container, {todo:todo}, marker, todo.id); ids[todo.id] = markers.length; idxs[markers.length] = todo.id; markers.push(marker); todos.push(todo); values.push(todo.data || {}); updated = true; }; // return a "marker todo" by its index this.todo = function(index){ return todos[index]; }; // return a "marker value" by its index this.value = function(index){ return values[index]; }; // return a marker by its index this.marker = function(index){ if (index in markers) { prepareMarker(index); return markers[index]; } return false; }; // return a marker by its index this.markerIsSet = function(index){ return Boolean(markers[index]); }; // store a new marker instead if the default "false" this.setMarker = function(index, marker){ markers[index] = marker; }; // link the visible overlay to the logical data (to hide overlays later) this.store = function(cluster, obj, shadow){ store[cluster.ref] = {obj:obj, shadow:shadow}; }; // free all objects this.free = function(){ for(var i = 0; i < events.length; i++){ google.maps.event.removeListener(events[i]); } events = []; $.each(store, function(key){ flush(key); }); store = {}; $.each(todos, function(i){ todos[i] = null; }); todos = []; $.each(markers, function(i){ if (markers[i]){ // false = removed markers[i].setMap(null); delete markers[i]; } }); markers = []; $.each(values, function(i){ delete values[i]; }); values = []; ids = {}; idxs = {}; }; // link the display function this.filter = function(f){ ffilter = f; redraw(); }; // enable/disable the clustering feature this.enable = function(value){ if (enabled != value){ enabled = value; redraw(); } }; // link the display function this.display = function(f){ fdisplay = f; }; // link the errorfunction this.error = function(f){ ferror = f; }; // lock the redraw this.beginUpdate = function(){ updating = true; }; // unlock the redraw this.endUpdate = function(){ updating = false; if (updated){ redraw(); } }; // extends current bounds with internal markers this.autofit = function(bounds){ for(var i=0; i raw.maxZoom), previousKeys = getStoreKeys(), i, j, k, indexes, check = false, bounds, cluster, position, previous, lat, lng, loop; // reset flag updated = false; if (zoom > 3){ // extend the bounds of the visible map to manage clusters near the boundaries bounds = extendsMapBounds(); // check contain only if boundaries are valid check = bounds.getSouthWest().lng() < bounds.getNorthEast().lng(); } // calculate positions of "visibles" markers (in extended bounds) for(i=0; i 1) && loop); } else { for(j=i; j [id, ...] objects = {}; // id => object function normalize(res) { return { id: res.id, name: res.name, object:res.obj, tag:res.tag, data:res.data }; } /** * add a mixed to the store **/ this.add = function(args, name, obj, sub){ var todo = args.todo || {}, id = globalId(todo.id); if (!store[name]){ store[name] = []; } if (id in objects){ // object already exists: remove it this.clearById(id); } objects[id] = {obj:obj, sub:sub, name:name, id:id, tag:todo.tag, data:todo.data}; store[name].push(id); return id; }; /** * return a stored object by its id **/ this.getById = function(id, sub, full){ if (id in objects){ if (sub) { return objects[id].sub } else if (full) { return normalize(objects[id]); } return objects[id].obj; } return false; }; /** * return a stored value **/ this.get = function(name, last, tag, full){ var n, id, check = ftag(tag); if (!store[name] || !store[name].length){ return null; } n = store[name].length; while(n){ n--; id = store[name][last ? n : store[name].length - n - 1]; if (id && objects[id]){ if (check && !check(objects[id].tag)){ continue; } return full ? normalize(objects[id]) : objects[id].obj; } } return null; }; /** * return all stored values **/ this.all = function(name, tag, full){ var result = [], check = ftag(tag), find = function(n){ var i, id; for(i=0; i= 0; idx--){ id = store[name][idx]; if ( check(objects[id].tag) ){ break; } } } else { for(idx = 0; idx < store[name].length; idx++){ id = store[name][idx]; if (check(objects[id].tag)){ break; } } } } else { idx = pop ? store[name].length - 1 : 0; } if ( !(idx in store[name]) ) { return false; } return this.clearById(store[name][idx], idx); }; /** * remove object from the store by its id **/ this.clearById = function(id, idx){ if (id in objects){ var i, name = objects[id].name; for(i=0; idx === undef && i= 0 || !list.length)) { for(var idx in store["clusterer"]){ objects[store["clusterer"][idx]].obj.clear(last, first, tag); } } }; } /***************************************************************************/ /* GMAP3 GLOBALS */ /***************************************************************************/ var services = {}, geocoderCache = new GeocoderCache(); //-----------------------------------------------------------------------// // Service tools //-----------------------------------------------------------------------// function geocoder(){ if (!services.geocoder) { services.geocoder = new google.maps.Geocoder(); } return services.geocoder; } function directionsService(){ if (!services.directionsService) { services.directionsService = new google.maps.DirectionsService(); } return services.directionsService; } function elevationService(){ if (!services.elevationService) { services.elevationService = new google.maps.ElevationService(); } return services.elevationService; } function maxZoomService(){ if (!services.maxZoomService) { services.maxZoomService = new google.maps.MaxZoomService(); } return services.maxZoomService; } function distanceMatrixService(){ if (!services.distanceMatrixService) { services.distanceMatrixService = new google.maps.DistanceMatrixService(); } return services.distanceMatrixService; } //-----------------------------------------------------------------------// // Unit tools //-----------------------------------------------------------------------// function error(){ if (defaults.verbose){ var i, err = []; if (window.console && (typeof console.error === "function") ){ for(i=0; i= 0){ return true; } } return false; } return $.inArray(val, tag) >= 0; } } } /** * convert mixed [ lat, lng ] objet to google.maps.LatLng **/ function toLatLng (mixed, emptyReturnMixed, noFlat){ var empty = emptyReturnMixed ? mixed : null; if (!mixed || (typeof mixed === "string")){ return empty; } // defined latLng if (mixed.latLng) { return toLatLng(mixed.latLng); } // google.maps.LatLng object if (mixed instanceof google.maps.LatLng) { return mixed; } // {lat:X, lng:Y} object else if ( numeric(mixed.lat) ) { return new google.maps.LatLng(mixed.lat, mixed.lng); } // [X, Y] object else if ( !noFlat && $.isArray(mixed)){ if ( !numeric(mixed[0]) || !numeric(mixed[1]) ) { return empty; } return new google.maps.LatLng(mixed[0], mixed[1]); } return empty; } /** * convert mixed [ sw, ne ] object by google.maps.LatLngBounds **/ function toLatLngBounds(mixed){ var ne, sw; if (!mixed || mixed instanceof google.maps.LatLngBounds) { return mixed || null; } if ($.isArray(mixed)){ if (mixed.length == 2){ ne = toLatLng(mixed[0]); sw = toLatLng(mixed[1]); } else if (mixed.length == 4){ ne = toLatLng([mixed[0], mixed[1]]); sw = toLatLng([mixed[2], mixed[3]]); } } else { if ( ("ne" in mixed) && ("sw" in mixed) ){ ne = toLatLng(mixed.ne); sw = toLatLng(mixed.sw); } else if ( ("n" in mixed) && ("e" in mixed) && ("s" in mixed) && ("w" in mixed) ){ ne = toLatLng([mixed.n, mixed.e]); sw = toLatLng([mixed.s, mixed.w]); } } if (ne && sw){ return new google.maps.LatLngBounds(sw, ne); } return null; } /** * resolveLatLng **/ function resolveLatLng(ctx, method, runLatLng, args, attempt){ var latLng = runLatLng ? toLatLng(args.todo, false, true) : false, conf = latLng ? {latLng:latLng} : (args.todo.address ? (typeof(args.todo.address) === "string" ? {address:args.todo.address} : args.todo.address) : false), cache = conf ? geocoderCache.get(conf) : false, that = this; if (conf){ attempt = attempt || 0; // convert undefined to int if (cache){ args.latLng = cache.results[0].geometry.location; args.results = cache.results; args.status = cache.status; method.apply(ctx, [args]); } else { if (conf.location){ conf.location = toLatLng(conf.location); } if (conf.bounds){ conf.bounds = toLatLngBounds(conf.bounds); } geocoder().geocode( conf, function(results, status) { if (status === google.maps.GeocoderStatus.OK){ geocoderCache.store(conf, {results:results, status:status}); args.latLng = results[0].geometry.location; args.results = results; args.status = status; method.apply(ctx, [args]); } else if ( (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) && (attempt < defaults.queryLimit.attempt) ){ setTimeout( function(){ resolveLatLng.apply(that, [ctx, method, runLatLng, args, attempt+1]); }, defaults.queryLimit.delay + Math.floor(Math.random() * defaults.queryLimit.random) ); } else { error("geocode failed", status, conf); args.latLng = args.results = false; args.status = status; method.apply(ctx, [args]); } } ); } } else { args.latLng = toLatLng(args.todo, false, true); method.apply(ctx, [args]); } } function resolveAllLatLng(list, ctx, method, args){ var that = this, i = -1; function resolve(){ // look for next address to resolve do{ i++; }while( (i < list.length) && !("address" in list[i]) ); // no address found, so run method if (i >= list.length){ method.apply(ctx, [args]); return; } resolveLatLng( that, function(args){ delete args.todo; $.extend(list[i], args); resolve.apply(that, []); // resolve next (using apply avoid too much recursion) }, true, {todo:list[i]} ); } resolve(); } /** * geolocalise the user and return a LatLng **/ function geoloc(ctx, method, args){ var is_echo = false; // sometime, a kind of echo appear, this trick will notice once the first call is run to ignore the next one if (navigator && navigator.geolocation){ navigator.geolocation.getCurrentPosition( function(pos) { if (is_echo){ return; } is_echo = true; args.latLng = new google.maps.LatLng(pos.coords.latitude,pos.coords.longitude); method.apply(ctx, [args]); }, function() { if (is_echo){ return; } is_echo = true; args.latLng = false; method.apply(ctx, [args]); }, args.opts.getCurrentPosition ); } else { args.latLng = false; method.apply(ctx, [args]); } } /***************************************************************************/ /* GMAP3 */ /***************************************************************************/ function Gmap3($this){ var that = this, stack = new Stack(), store = new Store(), map = null, task; //-----------------------------------------------------------------------// // Stack tools //-----------------------------------------------------------------------// /** * store actions to execute in a stack manager **/ this._plan = function(list){ for(var k = 0; k < list.length; k++) { stack.add(new Task(that, end, list[k])); } run(); }; /** * if not running, start next action in stack **/ function run(){ if (!task && (task = stack.get())){ task.run(); } } /** * called when action in finished, to acknoledge the current in stack and start next one **/ function end(){ task = null; stack.ack(); run.call(that); // restart to high level scope } //-----------------------------------------------------------------------// // Tools //-----------------------------------------------------------------------// /** * execute callback functions **/ function callback(args){ if (args.todo.callback) { var params = Array.prototype.slice.call(arguments, 1); if (typeof args.todo.callback === "function") { args.todo.callback.apply($this, params); } else if ($.isArray(args.todo.callback)) { if (typeof args.todo.callback[1] === "function") { args.todo.callback[1].apply(args.todo.callback[0], params); } } } } /** * execute ending functions **/ function manageEnd(args, obj, id){ if (id){ attachEvents($this, args, obj, id); } callback(args, obj); task.ack(obj); } /** * initialize the map if not yet initialized **/ function newMap(latLng, args){ args = args || {}; if (map) { if (args.todo && args.todo.options){ if (args.todo.options.center) { args.todo.options.center = toLatLng(args.todo.options.center); } map.setOptions(args.todo.options); } } else { var opts = args.opts || $.extend(true, {}, defaults.map, args.todo && args.todo.options ? args.todo.options : {}); opts.center = latLng || toLatLng(opts.center); map = new defaults.classes.Map($this.get(0), opts); } } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = => function with latLng resolution = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /** * Initialize google.maps.Map object **/ this.map = function(args){ newMap(args.latLng, args); attachEvents($this, args, map); manageEnd(args, map); }; /** * destroy an existing instance **/ this.destroy = function(args){ store.clear(); $this.empty(); if (map){ map = null; } manageEnd(args, true); }; /** * add an infowindow **/ this.infowindow = function(args){ var objs = [], multiple = "values" in args.todo; if (!multiple){ if (args.latLng) { args.opts.position = args.latLng; } args.todo.values = [{options:args.opts}]; } $.each(args.todo.values, function(i, value){ var id, obj, todo = tuple(args, value); todo.options.position = todo.options.position ? toLatLng(todo.options.position) : toLatLng(value.latLng); if (!map){ newMap(todo.options.position); } obj = new defaults.classes.InfoWindow(todo.options); if (obj && ((todo.open === undef) || todo.open)){ if (multiple){ obj.open(map, todo.anchor ? todo.anchor : undef); } else { obj.open(map, todo.anchor ? todo.anchor : (args.latLng ? undef : (args.session.marker ? args.session.marker : undef))); } } objs.push(obj); id = store.add({todo:todo}, "infowindow", obj); attachEvents($this, {todo:todo}, obj, id); }); manageEnd(args, multiple ? objs : objs[0]); }; /** * add a circle **/ this.circle = function(args){ var objs = [], multiple = "values" in args.todo; if (!multiple){ args.opts.center = args.latLng || toLatLng(args.opts.center); args.todo.values = [{options:args.opts}]; } if (!args.todo.values.length){ manageEnd(args, false); return; } $.each(args.todo.values, function(i, value){ var id, obj, todo = tuple(args, value); todo.options.center = todo.options.center ? toLatLng(todo.options.center) : toLatLng(value); if (!map){ newMap(todo.options.center); } todo.options.map = map; obj = new defaults.classes.Circle(todo.options); objs.push(obj); id = store.add({todo:todo}, "circle", obj); attachEvents($this, {todo:todo}, obj, id); }); manageEnd(args, multiple ? objs : objs[0]); }; /** * add an overlay **/ this.overlay = function(args, internal){ var objs = [], multiple = "values" in args.todo; if (!multiple){ args.todo.values = [{latLng: args.latLng, options: args.opts}]; } if (!args.todo.values.length){ manageEnd(args, false); return; } if (!OverlayView.__initialised) { OverlayView.prototype = new defaults.classes.OverlayView(); OverlayView.__initialised = true; } $.each(args.todo.values, function(i, value){ var id, obj, todo = tuple(args, value), $div = $(document.createElement("div")).css({ border: "none", borderWidth: "0px", position: "absolute" }); $div.append(todo.options.content); obj = new OverlayView(map, todo.options, toLatLng(todo) || toLatLng(value), $div); objs.push(obj); $div = null; // memory leak if (!internal){ id = store.add(args, "overlay", obj); attachEvents($this, {todo:todo}, obj, id); } }); if (internal){ return objs[0]; } manageEnd(args, multiple ? objs : objs[0]); }; /** * returns address structure from latlng **/ this.getaddress = function(args){ callback(args, args.results, args.status); task.ack(); }; /** * returns latlng from an address **/ this.getlatlng = function(args){ callback(args, args.results, args.status); task.ack(); }; /** * return the max zoom of a location **/ this.getmaxzoom = function(args){ maxZoomService().getMaxZoomAtLatLng( args.latLng, function(result) { callback(args, result.status === google.maps.MaxZoomStatus.OK ? result.zoom : false, status); task.ack(); } ); }; /** * return the elevation of a location **/ this.getelevation = function(args){ var i, locations = [], f = function(results, status){ callback(args, status === google.maps.ElevationStatus.OK ? results : false, status); task.ack(); }; if (args.latLng){ locations.push(args.latLng); } else { locations = array(args.todo.locations || []); for(i=0; i function without latLng resolution = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /** * define defaults values **/ this.defaults = function(args){ $.each(args.todo, function(name, value){ if (typeof defaults[name] === "object"){ defaults[name] = $.extend({}, defaults[name], value); } else { defaults[name] = value; } }); task.ack(true); }; /** * add a rectangle **/ this.rectangle = function(args){ var objs = [], multiple = "values" in args.todo; if (!multiple){ args.todo.values = [{options:args.opts}]; } if (!args.todo.values.length){ manageEnd(args, false); return; } $.each(args.todo.values, function(i, value){ var id, obj, todo = tuple(args, value); todo.options.bounds = todo.options.bounds ? toLatLngBounds(todo.options.bounds) : toLatLngBounds(value); if (!map){ newMap(todo.options.bounds.getCenter()); } todo.options.map = map; obj = new defaults.classes.Rectangle(todo.options); objs.push(obj); id = store.add({todo:todo}, "rectangle", obj); attachEvents($this, {todo:todo}, obj, id); }); manageEnd(args, multiple ? objs : objs[0]); }; /** * add a polygone / polyline **/ function poly(args, poly, path){ var objs = [], multiple = "values" in args.todo; if (!multiple){ args.todo.values = [{options:args.opts}]; } if (!args.todo.values.length){ manageEnd(args, false); return; } newMap(); $.each(args.todo.values, function(_, value){ var id, i, j, obj, todo = tuple(args, value); if (todo.options[path]){ if (todo.options[path][0][0] && $.isArray(todo.options[path][0][0])){ for(i=0; i b}); // external calculator if (todo.calculator){ calculator = function(indexes){ var data = []; $.each(indexes, function(i, index){ data.push(internalClusterer.value(index)); }); return todo.calculator.apply($this, [data]); }; } else { calculator = function(indexes){ return indexes.length; }; } // set error function internalClusterer.error(function(){ error.apply(that, arguments); }); // set display function internalClusterer.display(function(cluster){ var i, style, atodo, obj, offset, cnt = calculator(cluster.indexes); // look for the style to use if (raw.force || cnt > 1) { for(i = 0; i < thresholds.length; i++) { if (thresholds[i] <= cnt) { style = styles[thresholds[i]]; } } } if (style){ offset = style.offset || [-style.width/2, -style.height/2]; // create a custom overlay command // nb: 2 extends are faster that a deeper extend atodo = $.extend({}, todo); atodo.options = $.extend({ pane: "overlayLayer", content:style.content ? style.content.replace("CLUSTER_COUNT", cnt) : "", offset:{ x: ("x" in offset ? offset.x : offset[0]) || 0, y: ("y" in offset ? offset.y : offset[1]) || 0 } }, todo.options || {}); obj = that.overlay({todo:atodo, opts:atodo.options, latLng:toLatLng(cluster)}, true); atodo.options.pane = "floatShadow"; atodo.options.content = $(document.createElement("div")).width(style.width+"px").height(style.height+"px").css({cursor:"pointer"}); shadow = that.overlay({todo:atodo, opts:atodo.options, latLng:toLatLng(cluster)}, true); // store data to the clusterer todo.data = { latLng: toLatLng(cluster), markers:[] }; $.each(cluster.indexes, function(i, index){ todo.data.markers.push(internalClusterer.value(index)); if (internalClusterer.markerIsSet(index)){ internalClusterer.marker(index).setMap(null); } }); attachEvents($this, {todo:todo}, shadow, undef, {main:obj, shadow:shadow}); internalClusterer.store(cluster, obj, shadow); } else { $.each(cluster.indexes, function(i, index){ internalClusterer.marker(index).setMap(map); }); } }); return internalClusterer; } /** * add a marker **/ this.marker = function(args){ var multiple = "values" in args.todo, init = !map; if (!multiple){ args.opts.position = args.latLng || toLatLng(args.opts.position); args.todo.values = [{options:args.opts}]; } if (!args.todo.values.length){ manageEnd(args, false); return; } if (init){ newMap(); } if (args.todo.cluster && !map.getBounds()){ // map not initialised => bounds not available : wait for map if clustering feature is required google.maps.event.addListenerOnce(map, "bounds_changed", function() { that.marker.apply(that, [args]); }); return; } if (args.todo.cluster){ var clusterer, internalClusterer; if (args.todo.cluster instanceof Clusterer){ clusterer = args.todo.cluster; internalClusterer = store.getById(clusterer.id(), true); } else { internalClusterer = createClusterer(args.todo.cluster); clusterer = new Clusterer(globalId(args.todo.id, true), internalClusterer); store.add(args, "clusterer", clusterer, internalClusterer); } internalClusterer.beginUpdate(); $.each(args.todo.values, function(i, value){ var todo = tuple(args, value); todo.options.position = todo.options.position ? toLatLng(todo.options.position) : toLatLng(value); if (todo.options.position) { todo.options.map = map; if (init){ map.setCenter(todo.options.position); init = false; } internalClusterer.add(todo, value); } }); internalClusterer.endUpdate(); manageEnd(args, clusterer); } else { var objs = []; $.each(args.todo.values, function(i, value){ var id, obj, todo = tuple(args, value); todo.options.position = todo.options.position ? toLatLng(todo.options.position) : toLatLng(value); if (todo.options.position) { todo.options.map = map; if (init){ map.setCenter(todo.options.position); init = false; } obj = new defaults.classes.Marker(todo.options); objs.push(obj); id = store.add({todo:todo}, "marker", obj); attachEvents($this, {todo:todo}, obj, id); } }); manageEnd(args, multiple ? objs : objs[0]); } }; /** * return a route **/ this.getroute = function(args){ args.opts.origin = toLatLng(args.opts.origin, true); args.opts.destination = toLatLng(args.opts.destination, true); directionsService().route( args.opts, function(results, status) { callback(args, status == google.maps.DirectionsStatus.OK ? results : false, status); task.ack(); } ); }; /** * add a direction renderer **/ this.directionsrenderer = function(args){ args.opts.map = map; var id, obj = new google.maps.DirectionsRenderer(args.opts); if (args.todo.divId){ obj.setPanel(document.getElementById(args.todo.divId)); } else if (args.todo.container){ obj.setPanel($(args.todo.container).get(0)); } id = store.add(args, "directionsrenderer", obj); manageEnd(args, obj, id); }; /** * returns latLng of the user **/ this.getgeoloc = function(args){ manageEnd(args, args.latLng); }; /** * add a style **/ this.styledmaptype = function(args){ newMap(); var obj = new defaults.classes.StyledMapType(args.todo.styles, args.opts); map.mapTypes.set(args.todo.id, obj); manageEnd(args, obj); }; /** * add an imageMapType **/ this.imagemaptype = function(args){ newMap(); var obj = new defaults.classes.ImageMapType(args.opts); map.mapTypes.set(args.todo.id, obj); manageEnd(args, obj); }; /** * autofit a map using its overlays (markers, rectangles ...) **/ this.autofit = function(args){ var bounds = new google.maps.LatLngBounds(); $.each(store.all(), function(i, obj){ if (obj.getPosition){ bounds.extend(obj.getPosition()); } else if (obj.getBounds){ bounds.extend(obj.getBounds().getNorthEast()); bounds.extend(obj.getBounds().getSouthWest()); } else if (obj.getPaths){ obj.getPaths().forEach(function(path){ path.forEach(function(latLng){ bounds.extend(latLng); }); }); } else if (obj.getPath){ obj.getPath().forEach(function(latLng){ bounds.extend(latLng);"" }); } else if (obj.getCenter){ bounds.extend(obj.getCenter()); } else if (obj instanceof Clusterer){ obj = store.getById(obj.id(), true); if (obj){ obj.autofit(bounds); } } }); if (!bounds.isEmpty() && (!map.getBounds() || !map.getBounds().equals(bounds))){ if ("maxZoom" in args.todo){ // fitBouds Callback event => detect zoom level and check maxZoom google.maps.event.addListenerOnce( map, "bounds_changed", function() { if (this.getZoom() > args.todo.maxZoom){ this.setZoom(args.todo.maxZoom); } } ); } map.fitBounds(bounds); } manageEnd(args, true); }; /** * remove objects from a map **/ this.clear = function(args){ if (typeof args.todo === "string"){ if (store.clearById(args.todo) || store.objClearById(args.todo)){ manageEnd(args, true); return; } args.todo = {name:args.todo}; } if (args.todo.id){ $.each(array(args.todo.id), function(i, id){ store.clearById(id) || store.objClearById(id); }); } else { store.clear(array(args.todo.name), args.todo.last, args.todo.first, args.todo.tag); store.objClear(array(args.todo.name), args.todo.last, args.todo.first, args.todo.tag); } manageEnd(args, true); }; /** * run a function on each items selected **/ this.exec = function(args){ var that = this; $.each(array(args.todo.func), function(i, func){ $.each(that.get(args.todo, true, args.todo.hasOwnProperty("full") ? args.todo.full : true), function(j, res){ func.call($this, res); }); }); manageEnd(args, true); }; /** * return objects previously created **/ this.get = function(args, direct, full){ var name, res, todo = direct ? args : args.todo; if (!direct) { full = todo.full; } if (typeof todo === "string"){ res = store.getById(todo, false, full) || store.objGetById(todo); if (res === false){ name = todo; todo = {}; } } else { name = todo.name; } if (name === "map"){ res = map; } if (!res){ res = []; if (todo.id){ $.each(array(todo.id), function(i, id) { res.push(store.getById(id, false, full) || store.objGetById(id)); }); if (!$.isArray(todo.id)) { res = res[0]; } } else { $.each(name ? array(name) : [undef], function(i, aName) { var result; if (todo.first){ result = store.get(aName, false, todo.tag, full); if (result) res.push(result); } else if (todo.all){ $.each(store.all(aName, todo.tag, full), function(i, result){ res.push(result); }); } else { result = store.get(aName, true, todo.tag, full); if (result) res.push(result); } }); if (!todo.all && !$.isArray(name)) { res = res[0]; } } } res = $.isArray(res) || !todo.all ? res : [res]; if (direct){ return res; } else { manageEnd(args, res); } }; /** * return the distance between an origin and a destination * **/ this.getdistance = function(args){ var i; args.opts.origins = array(args.opts.origins); for(i=0; i https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/common.js?ver=1.1.1 jQuery(document).ready(function($){ $("body").on("click", function(e){ var t = $(e.target); $(".sel-content").hide(); $(".sel-arraow").removeClass("active"); if(t.hasClass("sel-arraow")){ t.addClass("active"); t.parents(".sel-box").find(".sel-content").show(); }; }); $(".sel-content") .find("li") .on("click", function(){ $(this) .parents(".sel-content") .hide() .parents(".sel-box") .find("input[type='text']") .val($(this).text()) .next() .val($(this).val()); }); $(window).scroll(function () { if ($(this).scrollTop() > 50) { $('#back-to-top').fadeIn(); } else { $('#back-to-top').fadeOut(); } }); // scroll body to 0px on click $('#back-to-top').click(function () { $('#back-to-top').tooltip('hide'); $('body,html').animate({ scrollTop: 0}, 800); return false; }); }); // source --> https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/jquery_javo_search.js?ver=0.0.1 /* * jQuery javo Search Plugin; v0.5.9 * Copyright (C) 2014 javo */ /* How to use (Examps) : $(".javo_property_output").javo_search({ url: "", loading: "/images/loading.gif", selFilter:$(".javo_sel_filter"), btnSubmit:$(".javo_search_field_submit"), txtKeyword:$("input[name='s']"), param:{ type:11, post_type:"property" } }); */ (function($){ $.fn.javo_search = function(d){ var a = $(this); var o = {}, p = {}, data={}; a.hide(); // Ajax Initialize o.type = "post"; o.dataType = "json"; o.url = d.url; o.success = function(data){ var bound = new google.maps.LatLngBounds(); var markers = new Array(); if(data.result == "success"){ a.fadeOut('fast', function(){ $(this).html(data.html).fadeIn('fast'); //$("html, body").animate({scrollTop:"0px"}, 500); }); }else{ a.html("Fail to load posts!"); }; if(typeof(d.map) != "undefined"){ var tar = d.map.val(); if(tar != ""){ if( typeof($(tar).get(0)) != "undefined" ){ var t = $(tar); if( typeof(jQuery.fn.gmap3) != "undefined"){ $.each(data.markers, function(i, v){ if(v.lat != "", v.lng != ""){ markers.push({latLng:[v.lat, v.lng], data:v.info, options:{icon:d.pin}}); bound.extend( new google.maps.LatLng(v.lat, v.lng)); } }); var m_options = { map:{ options:{ /*center: bound.getCenter(), */ zoom:6, mapTypeId: google.maps.MapTypeId.ROADMAP, mapTypeControl: false, navigationControl: true, scrollwheel: false, streetViewControl: true } },marker:{} }; m_options.marker = { values: markers, events:{ click: function(m, e, c){ var map = $(this).gmap3("get"), infoBox = $(this).gmap3({get:{name:"infowindow"}}); if(infoBox){ infoBox.open(map, m); infoBox.setContent(c.data); }else{ $(this).gmap3({ infowindow:{ anchor:m, options:{content: c.data, maxWidth:400} } }); }; } } }; $( d.map.val() ).height(300).gmap3(m_options); var _m = $( d.map.val() ).gmap3("get"); _m.fitBounds(bound); }else{ t.html("

Please, install to jQuery gmap3.

"); }; }; }; }; }; o.error = function(e){ alert("Error : " + e.state()); }; // Ajax Parametter Initialize p = $.extend({ type:1, ppp:10, featured:"image", page: "widget", post_type:"property", meta_term: false }, d.param); if(!d.noStart) rsearch(p); // Buttons Functions $("body").on("change", d.btnView, function(){ if(typeof(d.btnView) != "undefined"){ p.type = $(this).val(); rsearch(p); }; }); $("body").find(a).clearQueue().on("click", ".page-numbers", function(e){ e.preventDefault(); var pn = $(this).attr("href").split("="); p.page = (typeof(pn[1]) != "undefined")? pn[1] : 1; rsearch(p); }); $(d.btnSubmit).on("click", function(){ if(typeof(d.btnSubmit) != "undefined"){ rsearch(p); }; }); $(d.txtKeyword).on("keyup", d.txtKeyword, function(e){ if(e.keyCode == 13){ p.page = 1; rsearch(p); }; }); function rsearch(p){ if(typeof(d.selFilter) != "undefined"){ $.each(d.selFilter, function(){ if( this.value != "" && this.value > 0){ var n = this.name.replace("]", "").split("[")[1]; data[n] = this.value; }; }); p.tax = data; }; if(typeof(d.txtKeyword) != "undefined"){ p.keyword = d.txtKeyword.val(); }; if( typeof(d.post_id) != "undefined" ){ p.post_id = d.post_id; } if( d.meta_term != false && typeof(d.meta_term) != "undefined"){ data = {}; $.each(d.meta_term, function(i, v){ var n = this.name.replace("]", "").split("[")[1]; data[n] = this.value; }); p.term_meta = data; }; if( d.price_term != false && typeof(d.price_term) != "undefined"){ data = {}; $.each(d.price_term, function(i, v){ var n = this.name.replace("]", "").split("[")[1]; data[n] = this.value; }); p.price_term = data; }; if( d.area_term != false && typeof(d.area_term) != "undefined"){ data = {}; $.each(d.area_term, function(i, v){ var n = this.name.replace("]", "").split("[")[1]; data[n] = this.value; }); p.area_term = data; }; p.lang = $("html").attr("cur"); p.action = "post_list"; o.data = p; a.css("min-Height", "500px") .prepend(""); $.ajax(o); }; }; })(jQuery); // source --> https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/jquery.javo.mail.js?ver=0.0.1 (function($){ jQuery.javo_mail = function(d){ d = $.extend({ url:null , subejct: null , to: null , from: null , content: null , link: null , contact_phone: null , to_null_msg: "Please, to email adress." , from_null_msg: "Please, from email adress." , subject_null_msg: "Please, insert Subject(or name)" , content_null_msg: "Please, insert content" , successMsg: "Successfully !" , failMsg: "Sorry mail send failed" , confirmMsg: "Send this email ?" , hide:null , callback:null }, d); var options = {}; options.url = d.url; options.type = "post"; options.data = { subject: d.subject.val() , to: d.to , link: d.link , from: d.from.val() , content: d.content.val() , action: "send_mail" }; if( d.contact_phone != null ){ options.data.phone = d.contact_phone.val(); }; options.dataType = "json"; options.error = function(e){ alert('Server error : ' + e.state()); }; options.success = function(data){ if(data.result){ alert(d.successMsg); if( typeof(d.callback) == "function" ) d.callback(); }else{ alert(d.failMsg); }; }; function is_rm_null(str, msg){ if( typeof(str) != null && str.val() != "") return; str .css({ "border":"solid 1px #f00" , "background":"#fee" }) .focus(); alert(msg); return false; }; if( is_rm_null(d.subject, d.subject_null_msg ) == false ) return false; if( is_rm_null(d.from, d.from_null_msg ) == false ) return false; if( is_rm_null(d.content, d.content_null_msg ) == false ) return false; if(!confirm(d.confirmMsg)) return false; $.ajax(options); }; })(jQuery); // source --> https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/jquery.favorite.js?ver=1.0.0 (function($){ jQuery.fn.javo_favorite = function(o){ var _this = $(this); var options = {}; var param = {}; var atts = $.extend({ url:null , user: null , str_nologin: "Please login" , str_save: "Save" , str_unsave: "UnSave" , str_error: "Server Error!" , str_fail: "favorite regist fail." , mypage:false }, o); options.url = atts.url; options.type = "post"; options.dataType = "json"; options.error = function(e){ alert(atts.str_error); }; options.success = function(d){ if(d.return == "success"){ if( _this.hasClass("saved")){ _this.removeClass("saved"); _this.text(atts.str_save); }else{ _this.addClass("saved"); _this.text(atts.str_unsave); }; }else{ alert(atts.str_fail); }; _this.removeClass("disabled"); }; _this.on("click", function(){ if( atts.user == null || atts.user == "" || atts.user < 0){ alert(atts.str_nologin); return false; }; if(_this.hasClass("disabled")) return false; _this.addClass("disabled"); param.post_id = _this.data("post-id"); param.user_id = atts.user; param.reg = _this.hasClass("saved") ? null : true; param.action = "favorite"; options.data = param; if( atts.url != null ) $.ajax(options); }); } })(jQuery); // source --> https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/jquery.flexslider-min.js?ver=2.2.2 /* * jQuery FlexSlider v2.2.2 * Copyright 2012 WooThemes * Contributing Author: Tyler Smith */ !function(a){a.flexslider=function(b,c){var d=a(b);d.vars=a.extend({},a.flexslider.defaults,c);var j,e=d.vars.namespace,f=window.navigator&&window.navigator.msPointerEnabled&&window.MSGesture,g=("ontouchstart"in window||f||window.DocumentTouch&&document instanceof DocumentTouch)&&d.vars.touch,h="click touchend MSPointerUp",i="",k="vertical"===d.vars.direction,l=d.vars.reverse,m=d.vars.itemWidth>0,n="fade"===d.vars.animation,o=""!==d.vars.asNavFor,p={},q=!0;a.data(b,"flexslider",d),p={init:function(){d.animating=!1,d.currentSlide=parseInt(d.vars.startAt?d.vars.startAt:0,10),isNaN(d.currentSlide)&&(d.currentSlide=0),d.animatingTo=d.currentSlide,d.atEnd=0===d.currentSlide||d.currentSlide===d.last,d.containerSelector=d.vars.selector.substr(0,d.vars.selector.search(" ")),d.slides=a(d.vars.selector,d),d.container=a(d.containerSelector,d),d.count=d.slides.length,d.syncExists=a(d.vars.sync).length>0,"slide"===d.vars.animation&&(d.vars.animation="swing"),d.prop=k?"top":"marginLeft",d.args={},d.manualPause=!1,d.stopped=!1,d.started=!1,d.startTimeout=null,d.transitions=!d.vars.video&&!n&&d.vars.useCSS&&function(){var a=document.createElement("div"),b=["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"];for(var c in b)if(void 0!==a.style[b[c]])return d.pfx=b[c].replace("Perspective","").toLowerCase(),d.prop="-"+d.pfx+"-transform",!0;return!1}(),d.ensureAnimationEnd="",""!==d.vars.controlsContainer&&(d.controlsContainer=a(d.vars.controlsContainer).length>0&&a(d.vars.controlsContainer)),""!==d.vars.manualControls&&(d.manualControls=a(d.vars.manualControls).length>0&&a(d.vars.manualControls)),d.vars.randomize&&(d.slides.sort(function(){return Math.round(Math.random())-.5}),d.container.empty().append(d.slides)),d.doMath(),d.setup("init"),d.vars.controlNav&&p.controlNav.setup(),d.vars.directionNav&&p.directionNav.setup(),d.vars.keyboard&&(1===a(d.containerSelector).length||d.vars.multipleKeyboard)&&a(document).bind("keyup",function(a){var b=a.keyCode;if(!d.animating&&(39===b||37===b)){var c=39===b?d.getTarget("next"):37===b?d.getTarget("prev"):!1;d.flexAnimate(c,d.vars.pauseOnAction)}}),d.vars.mousewheel&&d.bind("mousewheel",function(a,b){a.preventDefault();var f=0>b?d.getTarget("next"):d.getTarget("prev");d.flexAnimate(f,d.vars.pauseOnAction)}),d.vars.pausePlay&&p.pausePlay.setup(),d.vars.slideshow&&d.vars.pauseInvisible&&p.pauseInvisible.init(),d.vars.slideshow&&(d.vars.pauseOnHover&&d.hover(function(){d.manualPlay||d.manualPause||d.pause()},function(){d.manualPause||d.manualPlay||d.stopped||d.play()}),d.vars.pauseInvisible&&p.pauseInvisible.isHidden()||(d.vars.initDelay>0?d.startTimeout=setTimeout(d.play,d.vars.initDelay):d.play())),o&&p.asNav.setup(),g&&d.vars.touch&&p.touch(),(!n||n&&d.vars.smoothHeight)&&a(window).bind("resize orientationchange focus",p.resize),d.find("img").attr("draggable","false"),setTimeout(function(){d.vars.start(d)},200)},asNav:{setup:function(){d.asNav=!0,d.animatingTo=Math.floor(d.currentSlide/d.move),d.currentItem=d.currentSlide,d.slides.removeClass(e+"active-slide").eq(d.currentItem).addClass(e+"active-slide"),f?(b._slider=d,d.slides.each(function(){var b=this;b._gesture=new MSGesture,b._gesture.target=b,b.addEventListener("MSPointerDown",function(a){a.preventDefault(),a.currentTarget._gesture&&a.currentTarget._gesture.addPointer(a.pointerId)},!1),b.addEventListener("MSGestureTap",function(b){b.preventDefault();var c=a(this),e=c.index();a(d.vars.asNavFor).data("flexslider").animating||c.hasClass("active")||(d.direction=d.currentItem=g&&c.hasClass(e+"active-slide")?d.flexAnimate(d.getTarget("prev"),!0):a(d.vars.asNavFor).data("flexslider").animating||c.hasClass(e+"active-slide")||(d.direction=d.currentItem'),d.pagingCount>1)for(var j=0;j':""+c+"","thumbnails"===d.vars.controlNav&&!0===d.vars.thumbCaptions){var k=g.attr("data-thumbcaption");""!=k&&void 0!=k&&(f+=''+k+"")}d.controlNavScaffold.append("
  • "+f+"
  • "),c++}d.controlsContainer?a(d.controlsContainer).append(d.controlNavScaffold):d.append(d.controlNavScaffold),p.controlNav.set(),p.controlNav.active(),d.controlNavScaffold.delegate("a, img",h,function(b){if(b.preventDefault(),""===i||i===b.type){var c=a(this),f=d.controlNav.index(c);c.hasClass(e+"active")||(d.direction=f>d.currentSlide?"next":"prev",d.flexAnimate(f,d.vars.pauseOnAction))}""===i&&(i=b.type),p.setToClearWatchedEvent()})},setupManual:function(){d.controlNav=d.manualControls,p.controlNav.active(),d.controlNav.bind(h,function(b){if(b.preventDefault(),""===i||i===b.type){var c=a(this),f=d.controlNav.index(c);c.hasClass(e+"active")||(d.direction=f>d.currentSlide?"next":"prev",d.flexAnimate(f,d.vars.pauseOnAction))}""===i&&(i=b.type),p.setToClearWatchedEvent()})},set:function(){var b="thumbnails"===d.vars.controlNav?"img":"a";d.controlNav=a("."+e+"control-nav li "+b,d.controlsContainer?d.controlsContainer:d)},active:function(){d.controlNav.removeClass(e+"active").eq(d.animatingTo).addClass(e+"active")},update:function(b,c){d.pagingCount>1&&"add"===b?d.controlNavScaffold.append(a("
  • "+d.count+"
  • ")):1===d.pagingCount?d.controlNavScaffold.find("li").remove():d.controlNav.eq(c).closest("li").remove(),p.controlNav.set(),d.pagingCount>1&&d.pagingCount!==d.controlNav.length?d.update(c,b):p.controlNav.active()}},directionNav:{setup:function(){var b=a('");d.controlsContainer?(a(d.controlsContainer).append(b),d.directionNav=a("."+e+"direction-nav li a",d.controlsContainer)):(d.append(b),d.directionNav=a("."+e+"direction-nav li a",d)),p.directionNav.update(),d.directionNav.bind(h,function(b){b.preventDefault();var c;(""===i||i===b.type)&&(c=a(this).hasClass(e+"next")?d.getTarget("next"):d.getTarget("prev"),d.flexAnimate(c,d.vars.pauseOnAction)),""===i&&(i=b.type),p.setToClearWatchedEvent()})},update:function(){var a=e+"disabled";1===d.pagingCount?d.directionNav.addClass(a).attr("tabindex","-1"):d.vars.animationLoop?d.directionNav.removeClass(a).removeAttr("tabindex"):0===d.animatingTo?d.directionNav.removeClass(a).filter("."+e+"prev").addClass(a).attr("tabindex","-1"):d.animatingTo===d.last?d.directionNav.removeClass(a).filter("."+e+"next").addClass(a).attr("tabindex","-1"):d.directionNav.removeClass(a).removeAttr("tabindex")}},pausePlay:{setup:function(){var b=a('
    ');d.controlsContainer?(d.controlsContainer.append(b),d.pausePlay=a("."+e+"pauseplay a",d.controlsContainer)):(d.append(b),d.pausePlay=a("."+e+"pauseplay a",d)),p.pausePlay.update(d.vars.slideshow?e+"pause":e+"play"),d.pausePlay.bind(h,function(b){b.preventDefault(),(""===i||i===b.type)&&(a(this).hasClass(e+"pause")?(d.manualPause=!0,d.manualPlay=!1,d.pause()):(d.manualPause=!1,d.manualPlay=!0,d.play())),""===i&&(i=b.type),p.setToClearWatchedEvent()})},update:function(a){"play"===a?d.pausePlay.removeClass(e+"pause").addClass(e+"play").html(d.vars.playText):d.pausePlay.removeClass(e+"play").addClass(e+"pause").html(d.vars.pauseText)}},touch:function(){function r(f){d.animating?f.preventDefault():(window.navigator.msPointerEnabled||1===f.touches.length)&&(d.pause(),g=k?d.h:d.w,i=Number(new Date),o=f.touches[0].pageX,p=f.touches[0].pageY,e=m&&l&&d.animatingTo===d.last?0:m&&l?d.limit-(d.itemW+d.vars.itemMargin)*d.move*d.animatingTo:m&&d.currentSlide===d.last?d.limit:m?(d.itemW+d.vars.itemMargin)*d.move*d.currentSlide:l?(d.last-d.currentSlide+d.cloneOffset)*g:(d.currentSlide+d.cloneOffset)*g,a=k?p:o,c=k?o:p,b.addEventListener("touchmove",s,!1),b.addEventListener("touchend",t,!1))}function s(b){o=b.touches[0].pageX,p=b.touches[0].pageY,h=k?a-p:a-o,j=k?Math.abs(h)f)&&(b.preventDefault(),!n&&d.transitions&&(d.vars.animationLoop||(h/=0===d.currentSlide&&0>h||d.currentSlide===d.last&&h>0?Math.abs(h)/g+2:1),d.setProps(e+h,"setTouch")))}function t(){if(b.removeEventListener("touchmove",s,!1),d.animatingTo===d.currentSlide&&!j&&null!==h){var k=l?-h:h,m=k>0?d.getTarget("next"):d.getTarget("prev");d.canAdvance(m)&&(Number(new Date)-i<550&&Math.abs(k)>50||Math.abs(k)>g/2)?d.flexAnimate(m,d.vars.pauseOnAction):n||d.flexAnimate(d.currentSlide,d.vars.pauseOnAction,!0)}b.removeEventListener("touchend",t,!1),a=null,c=null,h=null,e=null}function u(a){a.stopPropagation(),d.animating?a.preventDefault():(d.pause(),b._gesture.addPointer(a.pointerId),q=0,g=k?d.h:d.w,i=Number(new Date),e=m&&l&&d.animatingTo===d.last?0:m&&l?d.limit-(d.itemW+d.vars.itemMargin)*d.move*d.animatingTo:m&&d.currentSlide===d.last?d.limit:m?(d.itemW+d.vars.itemMargin)*d.move*d.currentSlide:l?(d.last-d.currentSlide+d.cloneOffset)*g:(d.currentSlide+d.cloneOffset)*g)}function v(a){a.stopPropagation();var c=a.target._slider;if(c){var d=-a.translationX,f=-a.translationY;return q+=k?f:d,h=q,j=k?Math.abs(q)500)&&(a.preventDefault(),!n&&c.transitions&&(c.vars.animationLoop||(h=q/(0===c.currentSlide&&0>q||c.currentSlide===c.last&&q>0?Math.abs(q)/g+2:1)),c.setProps(e+h,"setTouch"))),void 0)}}function w(b){b.stopPropagation();var d=b.target._slider;if(d){if(d.animatingTo===d.currentSlide&&!j&&null!==h){var f=l?-h:h,k=f>0?d.getTarget("next"):d.getTarget("prev");d.canAdvance(k)&&(Number(new Date)-i<550&&Math.abs(f)>50||Math.abs(f)>g/2)?d.flexAnimate(k,d.vars.pauseOnAction):n||d.flexAnimate(d.currentSlide,d.vars.pauseOnAction,!0)}a=null,c=null,h=null,e=null,q=0}}var a,c,e,g,h,i,j=!1,o=0,p=0,q=0;f?(b.style.msTouchAction="none",b._gesture=new MSGesture,b._gesture.target=b,b.addEventListener("MSPointerDown",u,!1),b._slider=d,b.addEventListener("MSGestureChange",v,!1),b.addEventListener("MSGestureEnd",w,!1)):b.addEventListener("touchstart",r,!1)},resize:function(){!d.animating&&d.is(":visible")&&(m||d.doMath(),n?p.smoothHeight():m?(d.slides.width(d.computedW),d.update(d.pagingCount),d.setProps()):k?(d.viewport.height(d.h),d.setProps(d.h,"setTotal")):(d.vars.smoothHeight&&p.smoothHeight(),d.newSlides.width(d.computedW),d.setProps(d.computedW,"setTotal")))},smoothHeight:function(a){if(!k||n){var b=n?d:d.viewport;a?b.animate({height:d.slides.eq(d.animatingTo).height()},a):b.height(d.slides.eq(d.animatingTo).height())}},sync:function(b){var c=a(d.vars.sync).data("flexslider"),e=d.animatingTo;switch(b){case"animate":c.flexAnimate(e,d.vars.pauseOnAction,!1,!0);break;case"play":c.playing||c.asNav||c.play();break;case"pause":c.pause()}},uniqueID:function(b){return b.find("[id]").each(function(){var b=a(this);b.attr("id",b.attr("id")+"_clone")}),b},pauseInvisible:{visProp:null,init:function(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;b0?setTimeout(d.play,d.vars.initDelay):d.play()})}},isHidden:function(){return document[p.pauseInvisible.visProp]||!1}},setToClearWatchedEvent:function(){clearTimeout(j),j=setTimeout(function(){i=""},3e3)}},d.flexAnimate=function(b,c,f,h,i){if(d.vars.animationLoop||b===d.currentSlide||(d.direction=b>d.currentSlide?"next":"prev"),o&&1===d.pagingCount&&(d.direction=d.currentItemd.limit&&1!==d.visible?d.limit:t):s=0===d.currentSlide&&b===d.count-1&&d.vars.animationLoop&&"next"!==d.direction?l?(d.count+d.cloneOffset)*q:0:d.currentSlide===d.last&&0===b&&d.vars.animationLoop&&"prev"!==d.direction?l?0:(d.count+1)*q:l?(d.count-1-b+d.cloneOffset)*q:(b+d.cloneOffset)*q,d.setProps(s,"",d.vars.animationSpeed),d.transitions?(d.vars.animationLoop&&d.atEnd||(d.animating=!1,d.currentSlide=d.animatingTo),d.container.unbind("webkitTransitionEnd transitionend"),d.container.bind("webkitTransitionEnd transitionend",function(){clearTimeout(d.ensureAnimationEnd),d.wrapup(q)}),clearTimeout(d.ensureAnimationEnd),d.ensureAnimationEnd=setTimeout(function(){d.wrapup(q)},d.vars.animationSpeed+100)):d.container.animate(d.args,d.vars.animationSpeed,d.vars.easing,function(){d.wrapup(q)})}d.vars.smoothHeight&&p.smoothHeight(d.vars.animationSpeed)}},d.wrapup=function(a){n||m||(0===d.currentSlide&&d.animatingTo===d.last&&d.vars.animationLoop?d.setProps(a,"jumpEnd"):d.currentSlide===d.last&&0===d.animatingTo&&d.vars.animationLoop&&d.setProps(a,"jumpStart")),d.animating=!1,d.currentSlide=d.animatingTo,d.vars.after(d)},d.animateSlides=function(){!d.animating&&q&&d.flexAnimate(d.getTarget("next"))},d.pause=function(){clearInterval(d.animatedSlides),d.animatedSlides=null,d.playing=!1,d.vars.pausePlay&&p.pausePlay.update("play"),d.syncExists&&p.sync("pause")},d.play=function(){d.playing&&clearInterval(d.animatedSlides),d.animatedSlides=d.animatedSlides||setInterval(d.animateSlides,d.vars.slideshowSpeed),d.started=d.playing=!0,d.vars.pausePlay&&p.pausePlay.update("pause"),d.syncExists&&p.sync("play")},d.stop=function(){d.pause(),d.stopped=!0},d.canAdvance=function(a,b){var c=o?d.pagingCount-1:d.last;return b?!0:o&&d.currentItem===d.count-1&&0===a&&"prev"===d.direction?!0:o&&0===d.currentItem&&a===d.pagingCount-1&&"next"!==d.direction?!1:a!==d.currentSlide||o?d.vars.animationLoop?!0:d.atEnd&&0===d.currentSlide&&a===c&&"next"!==d.direction?!1:d.atEnd&&d.currentSlide===c&&0===a&&"next"===d.direction?!1:!0:!1},d.getTarget=function(a){return d.direction=a,"next"===a?d.currentSlide===d.last?0:d.currentSlide+1:0===d.currentSlide?d.last:d.currentSlide-1},d.setProps=function(a,b,c){var e=function(){var c=a?a:(d.itemW+d.vars.itemMargin)*d.move*d.animatingTo,e=function(){if(m)return"setTouch"===b?a:l&&d.animatingTo===d.last?0:l?d.limit-(d.itemW+d.vars.itemMargin)*d.move*d.animatingTo:d.animatingTo===d.last?d.limit:c;switch(b){case"setTotal":return l?(d.count-1-d.currentSlide+d.cloneOffset)*a:(d.currentSlide+d.cloneOffset)*a;case"setTouch":return l?a:a;case"jumpEnd":return l?a:d.count*a;case"jumpStart":return l?d.count*a:a;default:return a}}();return-1*e+"px"}();d.transitions&&(e=k?"translate3d(0,"+e+",0)":"translate3d("+e+",0,0)",c=void 0!==c?c/1e3+"s":"0s",d.container.css("-"+d.pfx+"-transition-duration",c),d.container.css("transition-duration",c)),d.args[d.prop]=e,(d.transitions||void 0===c)&&d.container.css(d.args),d.container.css("transform",e)},d.setup=function(b){if(n)d.slides.css({width:"100%","float":"left",marginRight:"-100%",position:"relative"}),"init"===b&&(g?d.slides.css({opacity:0,display:"block",webkitTransition:"opacity "+d.vars.animationSpeed/1e3+"s ease",zIndex:1}).eq(d.currentSlide).css({opacity:1,zIndex:2}):d.slides.css({opacity:0,display:"block",zIndex:1}).eq(d.currentSlide).css({zIndex:2}).animate({opacity:1},d.vars.animationSpeed,d.vars.easing)),d.vars.smoothHeight&&p.smoothHeight();else{var c,f;"init"===b&&(d.viewport=a('
    ').css({overflow:"hidden",position:"relative"}).appendTo(d).append(d.container),d.cloneCount=0,d.cloneOffset=0,l&&(f=a.makeArray(d.slides).reverse(),d.slides=a(f),d.container.empty().append(d.slides))),d.vars.animationLoop&&!m&&(d.cloneCount=2,d.cloneOffset=1,"init"!==b&&d.container.find(".clone").remove(),p.uniqueID(d.slides.first().clone().addClass("clone").attr("aria-hidden","true")).appendTo(d.container),p.uniqueID(d.slides.last().clone().addClass("clone").attr("aria-hidden","true")).prependTo(d.container)),d.newSlides=a(d.vars.selector,d),c=l?d.count-1-d.currentSlide+d.cloneOffset:d.currentSlide+d.cloneOffset,k&&!m?(d.container.height(200*(d.count+d.cloneCount)+"%").css("position","absolute").width("100%"),setTimeout(function(){d.newSlides.css({display:"block"}),d.doMath(),d.viewport.height(d.h),d.setProps(c*d.h,"init")},"init"===b?100:0)):(d.container.width(200*(d.count+d.cloneCount)+"%"),d.setProps(c*d.computedW,"init"),setTimeout(function(){d.doMath(),d.newSlides.css({width:d.computedW,"float":"left",display:"block"}),d.vars.smoothHeight&&p.smoothHeight()},"init"===b?100:0))}m||d.slides.removeClass(e+"active-slide").eq(d.currentSlide).addClass(e+"active-slide"),d.vars.init(d)},d.doMath=function(){var a=d.slides.first(),b=d.vars.itemMargin,c=d.vars.minItems,e=d.vars.maxItems;d.w=void 0===d.viewport?d.width():d.viewport.width(),d.h=a.height(),d.boxPadding=a.outerWidth()-a.width(),m?(d.itemT=d.vars.itemWidth+b,d.minW=c?c*d.itemT:d.w,d.maxW=e?e*d.itemT-b:d.w,d.itemW=d.minW>d.w?(d.w-b*(c-1))/c:d.maxWd.w?d.w:d.vars.itemWidth,d.visible=Math.floor(d.w/d.itemW),d.move=d.vars.move>0&&d.vars.moved.w?d.itemW*(d.count-1)+b*(d.count-1):(d.itemW+b)*d.count-d.w-b):(d.itemW=d.w,d.pagingCount=d.count,d.last=d.count-1),d.computedW=d.itemW-d.boxPadding},d.update=function(a,b){d.doMath(),m||(ad.controlNav.length?p.controlNav.update("add"):("remove"===b&&!m||d.pagingCountd.last&&(d.currentSlide-=1,d.animatingTo-=1),p.controlNav.update("remove",d.last))),d.vars.directionNav&&p.directionNav.update()},d.addSlide=function(b,c){var e=a(b);d.count+=1,d.last=d.count-1,k&&l?void 0!==c?d.slides.eq(d.count-c).after(e):d.container.prepend(e):void 0!==c?d.slides.eq(c).before(e):d.container.append(e),d.update(c,"add"),d.slides=a(d.vars.selector+":not(.clone)",d),d.setup(),d.vars.added(d)},d.removeSlide=function(b){var c=isNaN(b)?d.slides.index(a(b)):b;d.count-=1,d.last=d.count-1,isNaN(b)?a(b,d.slides).remove():k&&l?d.slides.eq(d.last).remove():d.slides.eq(b).remove(),d.doMath(),d.update(c,"remove"),d.slides=a(d.vars.selector+":not(.clone)",d),d.setup(),d.vars.removed(d)},p.init()},a(window).blur(function(){focused=!1}).focus(function(){focused=!0}),a.flexslider.defaults={namespace:"flex-",selector:".slides > li",animation:"fade",easing:"swing",direction:"horizontal",reverse:!1,animationLoop:!0,smoothHeight:!1,startAt:0,slideshow:!0,slideshowSpeed:7e3,animationSpeed:600,initDelay:0,randomize:!1,thumbCaptions:!1,pauseOnAction:!0,pauseOnHover:!1,pauseInvisible:!0,useCSS:!0,touch:!0,video:!1,controlNav:!0,directionNav:!0,prevText:"Previous",nextText:"Next",keyboard:!0,multipleKeyboard:!1,mousewheel:!1,pausePlay:!1,pauseText:"Pause",playText:"Play",controlsContainer:"",manualControls:"",sync:"",asNavFor:"",itemWidth:0,itemMargin:0,minItems:1,maxItems:0,move:0,allowOneSlide:!0,start:function(){},before:function(){},after:function(){},end:function(){},added:function(){},removed:function(){},init:function(){}},a.fn.flexslider=function(b){if(void 0===b&&(b={}),"object"==typeof b)return this.each(function(){var c=a(this),d=b.selector?b.selector:".slides > li",e=c.find(d);1===e.length&&b.allowOneSlide===!0||0===e.length?(e.fadeIn(400),b.start&&b.start(c)):void 0===c.data("flexslider")&&new a.flexslider(this,b)});var c=a(this).data("flexslider");switch(b){case"play":c.play();break;case"pause":c.pause();break;case"stop":c.stop();break;case"next":c.flexAnimate(c.getTarget("next"),!0);break;case"prev":case"previous":c.flexAnimate(c.getTarget("prev"),!0);break;default:"number"==typeof b&&c.flexAnimate(b,!0)}}}(jQuery); // source --> https://www.mzmpropiedades.com.ar/wp-content/themes/javo-house/js/google.map.infobubble.js?ver=0.0.1 // ==ClosureCompiler== // @compilation_level ADVANCED_OPTIMIZATIONS // @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3.js // ==/ClosureCompiler== /** * @name CSS3 InfoBubble with tabs for Google Maps API V3 * @version 0.8 * @author Luke Mahe * @fileoverview * This library is a CSS Infobubble with tabs. It uses css3 rounded corners and * drop shadows and animations. It also allows tabs */ /* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A CSS3 InfoBubble v0.8 * @param {Object.=} opt_options Optional properties to set. * @extends {google.maps.OverlayView} * @constructor */ function InfoBubble(opt_options) { this.extend(InfoBubble, google.maps.OverlayView); this.tabs_ = []; this.activeTab_ = null; this.baseZIndex_ = 100; this.isOpen_ = false; var options = opt_options || {}; if (options['backgroundColor'] == undefined) { options['backgroundColor'] = this.BACKGROUND_COLOR_; } if (options['borderColor'] == undefined) { options['borderColor'] = this.BORDER_COLOR_; } if (options['borderRadius'] == undefined) { options['borderRadius'] = this.BORDER_RADIUS_; } if (options['borderWidth'] == undefined) { options['borderWidth'] = this.BORDER_WIDTH_; } if (options['padding'] == undefined) { options['padding'] = this.PADDING_; } if (options['arrowPosition'] == undefined) { options['arrowPosition'] = this.ARROW_POSITION_; } if (options['disableAutoPan'] == undefined) { options['disableAutoPan'] = false; } if (options['disableAnimation'] == undefined) { options['disableAnimation'] = false; } if (options['minWidth'] == undefined) { options['minWidth'] = this.MIN_WIDTH_; } if (options['shadowStyle'] == undefined) { options['shadowStyle'] = this.SHADOW_STYLE_; } if (options['arrowSize'] == undefined) { options['arrowSize'] = this.ARROW_SIZE_; } if (options['arrowStyle'] == undefined) { options['arrowStyle'] = this.ARROW_STYLE_; } this.buildDom_(); this.setValues(options); } window['InfoBubble'] = InfoBubble; /** * Default arrow size * @const * @private */ InfoBubble.prototype.ARROW_SIZE_ = 15; /** * Default arrow style * @const * @private */ InfoBubble.prototype.ARROW_STYLE_ = 0; /** * Default shadow style * @const * @private */ InfoBubble.prototype.SHADOW_STYLE_ = 1; /** * Default min width * @const * @private */ InfoBubble.prototype.MIN_WIDTH_ = 50; /** * Default arrow position * @const * @private */ InfoBubble.prototype.ARROW_POSITION_ = 50; /** * Default padding * @const * @private */ InfoBubble.prototype.PADDING_ = 10; /** * Default border width * @const * @private */ InfoBubble.prototype.BORDER_WIDTH_ = 1; /** * Default border color * @const * @private */ InfoBubble.prototype.BORDER_COLOR_ = '#ccc'; /** * Default border radius * @const * @private */ InfoBubble.prototype.BORDER_RADIUS_ = 10; /** * Default background color * @const * @private */ InfoBubble.prototype.BACKGROUND_COLOR_ = '#fff'; /** * Extends a objects prototype by anothers. * * @param {Object} obj1 The object to be extended. * @param {Object} obj2 The object to extend with. * @return {Object} The new extended object. * @ignore */ InfoBubble.prototype.extend = function(obj1, obj2) { return (function(object) { for (var property in object.prototype) { this.prototype[property] = object.prototype[property]; } return this; }).apply(obj1, [obj2]); }; /** * Builds the InfoBubble dom * @private */ InfoBubble.prototype.buildDom_ = function() { var bubble = this.bubble_ = document.createElement('DIV'); bubble.style['position'] = 'absolute'; bubble.style['zIndex'] = this.baseZIndex_; var tabsContainer = this.tabsContainer_ = document.createElement('DIV'); tabsContainer.style['position'] = 'relative'; // Close button var close = this.close_ = document.createElement('IMG'); close.style['position'] = 'absolute'; close.style['width'] = this.px(12); close.style['height'] = this.px(12); close.style['border'] = 0; close.style['zIndex'] = this.baseZIndex_ + 1; close.style['cursor'] = 'pointer'; close.src = 'http://maps.gstatic.com/intl/en_us/mapfiles/iw_close.gif'; var that = this; google.maps.event.addDomListener(close, 'click', function() { that.close(); google.maps.event.trigger(that, 'closeclick'); }); // Content area var contentContainer = this.contentContainer_ = document.createElement('DIV'); contentContainer.style['overflowX'] = 'auto'; contentContainer.style['overflowY'] = 'auto'; contentContainer.style['cursor'] = 'default'; contentContainer.style['clear'] = 'both'; contentContainer.style['position'] = 'relative'; var content = this.content_ = document.createElement('DIV'); contentContainer.appendChild(content); // Arrow var arrow = this.arrow_ = document.createElement('DIV'); arrow.style['position'] = 'relative'; var arrowOuter = this.arrowOuter_ = document.createElement('DIV'); var arrowInner = this.arrowInner_ = document.createElement('DIV'); var arrowSize = this.getArrowSize_(); arrowOuter.style['position'] = arrowInner.style['position'] = 'absolute'; arrowOuter.style['left'] = arrowInner.style['left'] = '50%'; arrowOuter.style['height'] = arrowInner.style['height'] = '0'; arrowOuter.style['width'] = arrowInner.style['width'] = '0'; arrowOuter.style['marginLeft'] = this.px(-arrowSize); arrowOuter.style['borderWidth'] = this.px(arrowSize); arrowOuter.style['borderBottomWidth'] = 0; // Shadow var bubbleShadow = this.bubbleShadow_ = document.createElement('DIV'); bubbleShadow.style['position'] = 'absolute'; // Hide the InfoBubble by default bubble.style['display'] = bubbleShadow.style['display'] = 'none'; bubble.appendChild(this.tabsContainer_); bubble.appendChild(close); bubble.appendChild(contentContainer); arrow.appendChild(arrowOuter); arrow.appendChild(arrowInner); bubble.appendChild(arrow); var stylesheet = document.createElement('style'); stylesheet.setAttribute('type', 'text/css'); /** * The animation for the infobubble * @type {string} */ this.animationName_ = '_ibani_' + Math.round(Math.random() * 10000); var css = '.' + this.animationName_ + '{-webkit-animation-name:' + this.animationName_ + ';-webkit-animation-duration:0.5s;' + '-webkit-animation-iteration-count:1;}' + '@-webkit-keyframes ' + this.animationName_ + ' {from {' + '-webkit-transform: scale(0)}50% {-webkit-transform: scale(1.2)}90% ' + '{-webkit-transform: scale(0.95)}to {-webkit-transform: scale(1)}}'; stylesheet.textContent = css; document.getElementsByTagName('head')[0].appendChild(stylesheet); }; /** * Sets the background class name * * @param {string} className The class name to set. */ InfoBubble.prototype.setBackgroundClassName = function(className) { this.set('backgroundClassName', className); }; InfoBubble.prototype['setBackgroundClassName'] = InfoBubble.prototype.setBackgroundClassName; /** * changed MVC callback */ InfoBubble.prototype.backgroundClassName_changed = function() { this.content_.className = this.get('backgroundClassName'); }; InfoBubble.prototype['backgroundClassName_changed'] = InfoBubble.prototype.backgroundClassName_changed; /** * Sets the class of the tab * * @param {string} className the class name to set. */ InfoBubble.prototype.setTabClassName = function(className) { this.set('tabClassName', className); }; InfoBubble.prototype['setTabClassName'] = InfoBubble.prototype.setTabClassName; /** * tabClassName changed MVC callback */ InfoBubble.prototype.tabClassName_changed = function() { this.updateTabStyles_(); }; InfoBubble.prototype['tabClassName_changed'] = InfoBubble.prototype.tabClassName_changed; /** * Gets the style of the arrow * * @private * @return {number} The style of the arrow. */ InfoBubble.prototype.getArrowStyle_ = function() { return parseInt(this.get('arrowStyle'), 10) || 0; }; /** * Sets the style of the arrow * * @param {number} style The style of the arrow. */ InfoBubble.prototype.setArrowStyle = function(style) { this.set('arrowStyle', style); }; InfoBubble.prototype['setArrowStyle'] = InfoBubble.prototype.setArrowStyle; /** * Arrow style changed MVC callback */ InfoBubble.prototype.arrowStyle_changed = function() { this.arrowSize_changed(); }; InfoBubble.prototype['arrowStyle_changed'] = InfoBubble.prototype.arrowStyle_changed; /** * Gets the size of the arrow * * @private * @return {number} The size of the arrow. */ InfoBubble.prototype.getArrowSize_ = function() { return parseInt(this.get('arrowSize'), 10) || 0; }; /** * Sets the size of the arrow * * @param {number} size The size of the arrow. */ InfoBubble.prototype.setArrowSize = function(size) { this.set('arrowSize', size); }; InfoBubble.prototype['setArrowSize'] = InfoBubble.prototype.setArrowSize; /** * Arrow size changed MVC callback */ InfoBubble.prototype.arrowSize_changed = function() { this.borderWidth_changed(); }; InfoBubble.prototype['arrowSize_changed'] = InfoBubble.prototype.arrowSize_changed; /** * Set the position of the InfoBubble arrow * * @param {number} pos The position to set. */ InfoBubble.prototype.setArrowPosition = function(pos) { this.set('arrowPosition', pos); }; InfoBubble.prototype['setArrowPosition'] = InfoBubble.prototype.setArrowPosition; /** * Get the position of the InfoBubble arrow * * @private * @return {number} The position.. */ InfoBubble.prototype.getArrowPosition_ = function() { return parseInt(this.get('arrowPosition'), 10) || 0; }; /** * arrowPosition changed MVC callback */ InfoBubble.prototype.arrowPosition_changed = function() { var pos = this.getArrowPosition_(); this.arrowOuter_.style['left'] = this.arrowInner_.style['left'] = pos + '%'; this.redraw_(); }; InfoBubble.prototype['arrowPosition_changed'] = InfoBubble.prototype.arrowPosition_changed; /** * Set the zIndex of the InfoBubble * * @param {number} zIndex The zIndex to set. */ InfoBubble.prototype.setZIndex = function(zIndex) { this.set('zIndex', zIndex); }; InfoBubble.prototype['setZIndex'] = InfoBubble.prototype.setZIndex; /** * Get the zIndex of the InfoBubble * * @return {number} The zIndex to set. */ InfoBubble.prototype.getZIndex = function() { return parseInt(this.get('zIndex'), 10) || this.baseZIndex_; }; /** * zIndex changed MVC callback */ InfoBubble.prototype.zIndex_changed = function() { var zIndex = this.getZIndex(); this.bubble_.style['zIndex'] = this.baseZIndex_ = zIndex; this.close_.style['zIndex'] = zIndex + 1; }; InfoBubble.prototype['zIndex_changed'] = InfoBubble.prototype.zIndex_changed; /** * Set the style of the shadow * * @param {number} shadowStyle The style of the shadow. */ InfoBubble.prototype.setShadowStyle = function(shadowStyle) { this.set('shadowStyle', shadowStyle); }; InfoBubble.prototype['setShadowStyle'] = InfoBubble.prototype.setShadowStyle; /** * Get the style of the shadow * * @private * @return {number} The style of the shadow. */ InfoBubble.prototype.getShadowStyle_ = function() { return parseInt(this.get('shadowStyle'), 10) || 0; }; /** * shadowStyle changed MVC callback */ InfoBubble.prototype.shadowStyle_changed = function() { var shadowStyle = this.getShadowStyle_(); var display = ''; var shadow = ''; var backgroundColor = ''; switch (shadowStyle) { case 0: display = 'none'; break; case 1: shadow = '40px 15px 10px rgba(33,33,33,0.3)'; backgroundColor = 'transparent'; break; case 2: shadow = '0 0 2px rgba(33,33,33,0.3)'; backgroundColor = 'rgba(33,33,33,0.35)'; break; } this.bubbleShadow_.style['boxShadow'] = this.bubbleShadow_.style['webkitBoxShadow'] = this.bubbleShadow_.style['MozBoxShadow'] = shadow; this.bubbleShadow_.style['backgroundColor'] = backgroundColor; if (this.isOpen_) { this.bubbleShadow_.style['display'] = display; this.draw(); } }; InfoBubble.prototype['shadowStyle_changed'] = InfoBubble.prototype.shadowStyle_changed; /** * Show the close button */ InfoBubble.prototype.showCloseButton = function() { this.set('hideCloseButton', false); }; InfoBubble.prototype['showCloseButton'] = InfoBubble.prototype.showCloseButton; /** * Hide the close button */ InfoBubble.prototype.hideCloseButton = function() { this.set('hideCloseButton', true); }; InfoBubble.prototype['hideCloseButton'] = InfoBubble.prototype.hideCloseButton; /** * hideCloseButton changed MVC callback */ InfoBubble.prototype.hideCloseButton_changed = function() { this.close_.style['display'] = this.get('hideCloseButton') ? 'none' : ''; }; InfoBubble.prototype['hideCloseButton_changed'] = InfoBubble.prototype.hideCloseButton_changed; /** * Set the background color * * @param {string} color The color to set. */ InfoBubble.prototype.setBackgroundColor = function(color) { if (color) { this.set('backgroundColor', color); } }; InfoBubble.prototype['setBackgroundColor'] = InfoBubble.prototype.setBackgroundColor; /** * backgroundColor changed MVC callback */ InfoBubble.prototype.backgroundColor_changed = function() { var backgroundColor = this.get('backgroundColor'); this.contentContainer_.style['backgroundColor'] = backgroundColor; this.arrowInner_.style['borderColor'] = backgroundColor + ' transparent transparent'; this.updateTabStyles_(); }; InfoBubble.prototype['backgroundColor_changed'] = InfoBubble.prototype.backgroundColor_changed; /** * Set the border color * * @param {string} color The border color. */ InfoBubble.prototype.setBorderColor = function(color) { if (color) { this.set('borderColor', color); } }; InfoBubble.prototype['setBorderColor'] = InfoBubble.prototype.setBorderColor; /** * borderColor changed MVC callback */ InfoBubble.prototype.borderColor_changed = function() { var borderColor = this.get('borderColor'); var contentContainer = this.contentContainer_; var arrowOuter = this.arrowOuter_; contentContainer.style['borderColor'] = borderColor; arrowOuter.style['borderColor'] = borderColor + ' transparent transparent'; contentContainer.style['borderStyle'] = arrowOuter.style['borderStyle'] = this.arrowInner_.style['borderStyle'] = 'solid'; this.updateTabStyles_(); }; InfoBubble.prototype['borderColor_changed'] = InfoBubble.prototype.borderColor_changed; /** * Set the radius of the border * * @param {number} radius The radius of the border. */ InfoBubble.prototype.setBorderRadius = function(radius) { this.set('borderRadius', radius); }; InfoBubble.prototype['setBorderRadius'] = InfoBubble.prototype.setBorderRadius; /** * Get the radius of the border * * @private * @return {number} The radius of the border. */ InfoBubble.prototype.getBorderRadius_ = function() { return parseInt(this.get('borderRadius'), 10) || 0; }; /** * borderRadius changed MVC callback */ InfoBubble.prototype.borderRadius_changed = function() { var borderRadius = this.getBorderRadius_(); var borderWidth = this.getBorderWidth_(); this.contentContainer_.style['borderRadius'] = this.contentContainer_.style['MozBorderRadius'] = this.contentContainer_.style['webkitBorderRadius'] = this.bubbleShadow_.style['borderRadius'] = this.bubbleShadow_.style['MozBorderRadius'] = this.bubbleShadow_.style['webkitBorderRadius'] = this.px(borderRadius); this.tabsContainer_.style['paddingLeft'] = this.tabsContainer_.style['paddingRight'] = this.px(borderRadius + borderWidth); this.redraw_(); }; InfoBubble.prototype['borderRadius_changed'] = InfoBubble.prototype.borderRadius_changed; /** * Get the width of the border * * @private * @return {number} width The width of the border. */ InfoBubble.prototype.getBorderWidth_ = function() { return parseInt(this.get('borderWidth'), 10) || 0; }; /** * Set the width of the border * * @param {number} width The width of the border. */ InfoBubble.prototype.setBorderWidth = function(width) { this.set('borderWidth', width); }; InfoBubble.prototype['setBorderWidth'] = InfoBubble.prototype.setBorderWidth; /** * borderWidth change MVC callback */ InfoBubble.prototype.borderWidth_changed = function() { var borderWidth = this.getBorderWidth_(); this.contentContainer_.style['borderWidth'] = this.px(borderWidth); this.tabsContainer_.style['top'] = this.px(borderWidth); this.updateArrowStyle_(); this.updateTabStyles_(); this.borderRadius_changed(); this.redraw_(); }; InfoBubble.prototype['borderWidth_changed'] = InfoBubble.prototype.borderWidth_changed; /** * Update the arrow style * @private */ InfoBubble.prototype.updateArrowStyle_ = function() { var borderWidth = this.getBorderWidth_(); var arrowSize = this.getArrowSize_(); var arrowStyle = this.getArrowStyle_(); var arrowOuterSizePx = this.px(arrowSize); var arrowInnerSizePx = this.px(Math.max(0, arrowSize - borderWidth)); var outer = this.arrowOuter_; var inner = this.arrowInner_; this.arrow_.style['marginTop'] = this.px(-borderWidth); outer.style['borderTopWidth'] = arrowOuterSizePx; inner.style['borderTopWidth'] = arrowInnerSizePx; // Full arrow or arrow pointing to the left if (arrowStyle == 0 || arrowStyle == 1) { outer.style['borderLeftWidth'] = arrowOuterSizePx; inner.style['borderLeftWidth'] = arrowInnerSizePx; } else { outer.style['borderLeftWidth'] = inner.style['borderLeftWidth'] = 0; } // Full arrow or arrow pointing to the right if (arrowStyle == 0 || arrowStyle == 2) { outer.style['borderRightWidth'] = arrowOuterSizePx; inner.style['borderRightWidth'] = arrowInnerSizePx; } else { outer.style['borderRightWidth'] = inner.style['borderRightWidth'] = 0; } if (arrowStyle < 2) { outer.style['marginLeft'] = this.px(-(arrowSize)); inner.style['marginLeft'] = this.px(-(arrowSize - borderWidth)); } else { outer.style['marginLeft'] = inner.style['marginLeft'] = 0; } // If there is no border then don't show thw outer arrow if (borderWidth == 0) { outer.style['display'] = 'none'; } else { outer.style['display'] = ''; } }; /** * Set the padding of the InfoBubble * * @param {number} padding The padding to apply. */ InfoBubble.prototype.setPadding = function(padding) { this.set('padding', padding); }; InfoBubble.prototype['setPadding'] = InfoBubble.prototype.setPadding; /** * Set the padding of the InfoBubble * * @private * @return {number} padding The padding to apply. */ InfoBubble.prototype.getPadding_ = function() { return parseInt(this.get('padding'), 10) || 0; }; /** * padding changed MVC callback */ InfoBubble.prototype.padding_changed = function() { var padding = this.getPadding_(); this.contentContainer_.style['padding'] = this.px(padding); this.updateTabStyles_(); this.redraw_(); }; InfoBubble.prototype['padding_changed'] = InfoBubble.prototype.padding_changed; /** * Add px extention to the number * * @param {number} num The number to wrap. * @return {string|number} A wrapped number. */ InfoBubble.prototype.px = function(num) { if (num) { // 0 doesn't need to be wrapped return num + 'px'; } return num; }; /** * Add events to stop propagation * @private */ InfoBubble.prototype.addEvents_ = function() { // We want to cancel all the events so they do not go to the map var events = ['mousedown', 'mousemove', 'mouseover', 'mouseout', 'mouseup', 'mousewheel', 'DOMMouseScroll', 'touchstart', 'touchend', 'touchmove', 'dblclick', 'contextmenu', 'click']; var bubble = this.bubble_; this.listeners_ = []; for (var i = 0, event; event = events[i]; i++) { this.listeners_.push( google.maps.event.addDomListener(bubble, event, function(e) { e.cancelBubble = true; if (e.stopPropagation) { e.stopPropagation(); } }) ); } }; /** * On Adding the InfoBubble to a map * Implementing the OverlayView interface */ InfoBubble.prototype.onAdd = function() { if (!this.bubble_) { this.buildDom_(); } this.addEvents_(); var panes = this.getPanes(); if (panes) { panes.floatPane.appendChild(this.bubble_); panes.floatShadow.appendChild(this.bubbleShadow_); } }; InfoBubble.prototype['onAdd'] = InfoBubble.prototype.onAdd; /** * Draw the InfoBubble * Implementing the OverlayView interface */ InfoBubble.prototype.draw = function() { var projection = this.getProjection(); if (!projection) { // The map projection is not ready yet so do nothing return; } var latLng = /** @type {google.maps.LatLng} */ (this.get('position')); if (!latLng) { this.close(); return; } var tabHeight = 0; if (this.activeTab_) { tabHeight = this.activeTab_.offsetHeight; } var anchorHeight = this.getAnchorHeight_(); var arrowSize = this.getArrowSize_(); var arrowPosition = this.getArrowPosition_(); arrowPosition = arrowPosition / 100; var pos = projection.fromLatLngToDivPixel(latLng); var width = this.contentContainer_.offsetWidth; var height = this.bubble_.offsetHeight; if (!width) { return; } // Adjust for the height of the info bubble var top = pos.y - (height + arrowSize); if (anchorHeight) { // If there is an anchor then include the height top -= anchorHeight; } var left = pos.x - (width * arrowPosition); this.bubble_.style['top'] = this.px(top); this.bubble_.style['left'] = this.px(left); var shadowStyle = parseInt(this.get('shadowStyle'), 10); switch (shadowStyle) { case 1: // Shadow is behind this.bubbleShadow_.style['top'] = this.px(top + tabHeight - 1); this.bubbleShadow_.style['left'] = this.px(left); this.bubbleShadow_.style['width'] = this.px(width); this.bubbleShadow_.style['height'] = this.px(this.contentContainer_.offsetHeight - arrowSize); break; case 2: // Shadow is below width = width * 0.8; if (anchorHeight) { this.bubbleShadow_.style['top'] = this.px(pos.y); } else { this.bubbleShadow_.style['top'] = this.px(pos.y + arrowSize); } this.bubbleShadow_.style['left'] = this.px(pos.x - width * arrowPosition); this.bubbleShadow_.style['width'] = this.px(width); this.bubbleShadow_.style['height'] = this.px(2); break; } }; InfoBubble.prototype['draw'] = InfoBubble.prototype.draw; /** * Removing the InfoBubble from a map */ InfoBubble.prototype.onRemove = function() { if (this.bubble_ && this.bubble_.parentNode) { this.bubble_.parentNode.removeChild(this.bubble_); } if (this.bubbleShadow_ && this.bubbleShadow_.parentNode) { this.bubbleShadow_.parentNode.removeChild(this.bubbleShadow_); } for (var i = 0, listener; listener = this.listeners_[i]; i++) { google.maps.event.removeListener(listener); } }; InfoBubble.prototype['onRemove'] = InfoBubble.prototype.onRemove; /** * Is the InfoBubble open * * @return {boolean} If the InfoBubble is open. */ InfoBubble.prototype.isOpen = function() { return this.isOpen_; }; InfoBubble.prototype['isOpen'] = InfoBubble.prototype.isOpen; /** * Close the InfoBubble */ InfoBubble.prototype.close = function() { if (this.bubble_) { this.bubble_.style['display'] = 'none'; // Remove the animation so we next time it opens it will animate again this.bubble_.className = this.bubble_.className.replace(this.animationName_, ''); } if (this.bubbleShadow_) { this.bubbleShadow_.style['display'] = 'none'; this.bubbleShadow_.className = this.bubbleShadow_.className.replace(this.animationName_, ''); } this.isOpen_ = false; }; InfoBubble.prototype['close'] = InfoBubble.prototype.close; /** * Open the InfoBubble (asynchronous). * * @param {google.maps.Map=} opt_map Optional map to open on. * @param {google.maps.MVCObject=} opt_anchor Optional anchor to position at. */ InfoBubble.prototype.open = function(opt_map, opt_anchor) { var that = this; window.setTimeout(function() { that.open_(opt_map, opt_anchor); }, 0); }; /** * Open the InfoBubble * @private * @param {google.maps.Map=} opt_map Optional map to open on. * @param {google.maps.MVCObject=} opt_anchor Optional anchor to position at. */ InfoBubble.prototype.open_ = function(opt_map, opt_anchor) { this.updateContent_(); if (opt_map) { this.setMap(opt_map); } if (opt_anchor) { this.set('anchor', opt_anchor); this.bindTo('anchorPoint', opt_anchor); this.bindTo('position', opt_anchor); } // Show the bubble and the show this.bubble_.style['display'] = this.bubbleShadow_.style['display'] = ''; var animation = !this.get('disableAnimation'); if (animation) { // Add the animation this.bubble_.className += ' ' + this.animationName_; this.bubbleShadow_.className += ' ' + this.animationName_; } this.redraw_(); this.isOpen_ = true; var pan = !this.get('disableAutoPan'); if (pan) { var that = this; window.setTimeout(function() { // Pan into view, done in a time out to make it feel nicer :) that.panToView(); }, 200); } }; InfoBubble.prototype['open'] = InfoBubble.prototype.open; /** * Set the position of the InfoBubble * * @param {google.maps.LatLng} position The position to set. */ InfoBubble.prototype.setPosition = function(position) { if (position) { this.set('position', position); } }; InfoBubble.prototype['setPosition'] = InfoBubble.prototype.setPosition; /** * Returns the position of the InfoBubble * * @return {google.maps.LatLng} the position. */ InfoBubble.prototype.getPosition = function() { return /** @type {google.maps.LatLng} */ (this.get('position')); }; InfoBubble.prototype['getPosition'] = InfoBubble.prototype.getPosition; /** * position changed MVC callback */ InfoBubble.prototype.position_changed = function() { this.draw(); }; InfoBubble.prototype['position_changed'] = InfoBubble.prototype.position_changed; /** * Pan the InfoBubble into view */ InfoBubble.prototype.panToView = function() { var projection = this.getProjection(); if (!projection) { // The map projection is not ready yet so do nothing return; } if (!this.bubble_) { // No Bubble yet so do nothing return; } var anchorHeight = this.getAnchorHeight_(); var height = this.bubble_.offsetHeight + anchorHeight; var map = this.get('map'); var mapDiv = map.getDiv(); var mapHeight = mapDiv.offsetHeight; var latLng = this.getPosition(); var centerPos = projection.fromLatLngToContainerPixel(map.getCenter()); var pos = projection.fromLatLngToContainerPixel(latLng); // Find out how much space at the top is free var spaceTop = centerPos.y - height; // Fine out how much space at the bottom is free var spaceBottom = mapHeight - centerPos.y; var needsTop = spaceTop < 0; var deltaY = 0; if (needsTop) { spaceTop *= -1; deltaY = (spaceTop + spaceBottom) / 2; } pos.y -= deltaY; latLng = projection.fromContainerPixelToLatLng(pos); if (map.getCenter() != latLng) { map.panTo(latLng); } }; InfoBubble.prototype['panToView'] = InfoBubble.prototype.panToView; /** * Converts a HTML string to a document fragment. * * @param {string} htmlString The HTML string to convert. * @return {Node} A HTML document fragment. * @private */ InfoBubble.prototype.htmlToDocumentFragment_ = function(htmlString) { htmlString = htmlString.replace(/^\s*([\S\s]*)\b\s*$/, '$1'); var tempDiv = document.createElement('DIV'); tempDiv.innerHTML = htmlString; if (tempDiv.childNodes.length == 1) { return /** @type {!Node} */ (tempDiv.removeChild(tempDiv.firstChild)); } else { var fragment = document.createDocumentFragment(); while (tempDiv.firstChild) { fragment.appendChild(tempDiv.firstChild); } return fragment; } }; /** * Removes all children from the node. * * @param {Node} node The node to remove all children from. * @private */ InfoBubble.prototype.removeChildren_ = function(node) { if (!node) { return; } var child; while (child = node.firstChild) { node.removeChild(child); } }; /** * Sets the content of the infobubble. * * @param {string|Node} content The content to set. */ InfoBubble.prototype.setContent = function(content) { this.set('content', content); }; InfoBubble.prototype['setContent'] = InfoBubble.prototype.setContent; /** * Get the content of the infobubble. * * @return {string|Node} The marker content. */ InfoBubble.prototype.getContent = function() { return /** @type {Node|string} */ (this.get('content')); }; InfoBubble.prototype['getContent'] = InfoBubble.prototype.getContent; /** * Sets the marker content and adds loading events to images */ InfoBubble.prototype.updateContent_ = function() { if (!this.content_) { // The Content area doesnt exist. return; } this.removeChildren_(this.content_); var content = this.getContent(); if (content) { if (typeof content == 'string') { content = this.htmlToDocumentFragment_(content); } this.content_.appendChild(content); var that = this; var images = this.content_.getElementsByTagName('IMG'); for (var i = 0, image; image = images[i]; i++) { // Because we don't know the size of an image till it loads, add a // listener to the image load so the marker can resize and reposition // itself to be the correct height. google.maps.event.addDomListener(image, 'load', function() { that.imageLoaded_(); }); } google.maps.event.trigger(this, 'domready'); } this.redraw_(); }; /** * Image loaded * @private */ InfoBubble.prototype.imageLoaded_ = function() { var pan = !this.get('disableAutoPan'); this.redraw_(); if (pan && (this.tabs_.length == 0 || this.activeTab_.index == 0)) { this.panToView(); } }; /** * Updates the styles of the tabs * @private */ InfoBubble.prototype.updateTabStyles_ = function() { if (this.tabs_ && this.tabs_.length) { for (var i = 0, tab; tab = this.tabs_[i]; i++) { this.setTabStyle_(tab.tab); } this.activeTab_.style['zIndex'] = this.baseZIndex_; var borderWidth = this.getBorderWidth_(); var padding = this.getPadding_() / 2; this.activeTab_.style['borderBottomWidth'] = 0; this.activeTab_.style['paddingBottom'] = this.px(padding + borderWidth); } }; /** * Sets the style of a tab * @private * @param {Element} tab The tab to style. */ InfoBubble.prototype.setTabStyle_ = function(tab) { var backgroundColor = this.get('backgroundColor'); var borderColor = this.get('borderColor'); var borderRadius = this.getBorderRadius_(); var borderWidth = this.getBorderWidth_(); var padding = this.getPadding_(); var marginRight = this.px(-(Math.max(padding, borderRadius))); var borderRadiusPx = this.px(borderRadius); var index = this.baseZIndex_; if (tab.index) { index -= tab.index; } // The styles for the tab var styles = { 'cssFloat': 'left', 'position': 'relative', 'cursor': 'pointer', 'backgroundColor': backgroundColor, 'border': this.px(borderWidth) + ' solid ' + borderColor, 'padding': this.px(padding / 2) + ' ' + this.px(padding), 'marginRight': marginRight, 'whiteSpace': 'nowrap', 'borderRadiusTopLeft': borderRadiusPx, 'MozBorderRadiusTopleft': borderRadiusPx, 'webkitBorderTopLeftRadius': borderRadiusPx, 'borderRadiusTopRight': borderRadiusPx, 'MozBorderRadiusTopright': borderRadiusPx, 'webkitBorderTopRightRadius': borderRadiusPx, 'zIndex': index, 'display': 'inline' }; for (var style in styles) { tab.style[style] = styles[style]; } var className = this.get('tabClassName'); if (className != undefined) { tab.className += ' ' + className; } }; /** * Add user actions to a tab * @private * @param {Object} tab The tab to add the actions to. */ InfoBubble.prototype.addTabActions_ = function(tab) { var that = this; tab.listener_ = google.maps.event.addDomListener(tab, 'click', function() { that.setTabActive_(this); }); }; /** * Set a tab at a index to be active * * @param {number} index The index of the tab. */ InfoBubble.prototype.setTabActive = function(index) { var tab = this.tabs_[index - 1]; if (tab) { this.setTabActive_(tab.tab); } }; InfoBubble.prototype['setTabActive'] = InfoBubble.prototype.setTabActive; /** * Set a tab to be active * @private * @param {Object} tab The tab to set active. */ InfoBubble.prototype.setTabActive_ = function(tab) { if (!tab) { this.setContent(''); this.updateContent_(); return; } var padding = this.getPadding_() / 2; var borderWidth = this.getBorderWidth_(); if (this.activeTab_) { var activeTab = this.activeTab_; activeTab.style['zIndex'] = this.baseZIndex_ - activeTab.index; activeTab.style['paddingBottom'] = this.px(padding); activeTab.style['borderBottomWidth'] = this.px(borderWidth); } tab.style['zIndex'] = this.baseZIndex_; tab.style['borderBottomWidth'] = 0; tab.style['marginBottomWidth'] = '-10px'; tab.style['paddingBottom'] = this.px(padding + borderWidth); this.setContent(this.tabs_[tab.index].content); this.updateContent_(); this.activeTab_ = tab; this.redraw_(); }; /** * Set the max width of the InfoBubble * * @param {number} width The max width. */ InfoBubble.prototype.setMaxWidth = function(width) { this.set('maxWidth', width); }; InfoBubble.prototype['setMaxWidth'] = InfoBubble.prototype.setMaxWidth; /** * maxWidth changed MVC callback */ InfoBubble.prototype.maxWidth_changed = function() { this.redraw_(); }; InfoBubble.prototype['maxWidth_changed'] = InfoBubble.prototype.maxWidth_changed; /** * Set the max height of the InfoBubble * * @param {number} height The max height. */ InfoBubble.prototype.setMaxHeight = function(height) { this.set('maxHeight', height); }; InfoBubble.prototype['setMaxHeight'] = InfoBubble.prototype.setMaxHeight; /** * maxHeight changed MVC callback */ InfoBubble.prototype.maxHeight_changed = function() { this.redraw_(); }; InfoBubble.prototype['maxHeight_changed'] = InfoBubble.prototype.maxHeight_changed; /** * Set the min width of the InfoBubble * * @param {number} width The min width. */ InfoBubble.prototype.setMinWidth = function(width) { this.set('minWidth', width); }; InfoBubble.prototype['setMinWidth'] = InfoBubble.prototype.setMinWidth; /** * minWidth changed MVC callback */ InfoBubble.prototype.minWidth_changed = function() { this.redraw_(); }; InfoBubble.prototype['minWidth_changed'] = InfoBubble.prototype.minWidth_changed; /** * Set the min height of the InfoBubble * * @param {number} height The min height. */ InfoBubble.prototype.setMinHeight = function(height) { this.set('minHeight', height); }; InfoBubble.prototype['setMinHeight'] = InfoBubble.prototype.setMinHeight; /** * minHeight changed MVC callback */ InfoBubble.prototype.minHeight_changed = function() { this.redraw_(); }; InfoBubble.prototype['minHeight_changed'] = InfoBubble.prototype.minHeight_changed; /** * Add a tab * * @param {string} label The label of the tab. * @param {string|Element} content The content of the tab. */ InfoBubble.prototype.addTab = function(label, content) { var tab = document.createElement('DIV'); tab.innerHTML = label; this.setTabStyle_(tab); this.addTabActions_(tab); this.tabsContainer_.appendChild(tab); this.tabs_.push({ label: label, content: content, tab: tab }); tab.index = this.tabs_.length - 1; tab.style['zIndex'] = this.baseZIndex_ - tab.index; if (!this.activeTab_) { this.setTabActive_(tab); } tab.className = tab.className + ' ' + this.animationName_; this.redraw_(); }; InfoBubble.prototype['addTab'] = InfoBubble.prototype.addTab; /** * Update a tab at a speicifc index * * @param {number} index The index of the tab. * @param {?string} opt_label The label to change to. * @param {?string} opt_content The content to update to. */ InfoBubble.prototype.updateTab = function(index, opt_label, opt_content) { if (!this.tabs_.length || index < 0 || index >= this.tabs_.length) { return; } var tab = this.tabs_[index]; if (opt_label != undefined) { tab.tab.innerHTML = tab.label = opt_label; } if (opt_content != undefined) { tab.content = opt_content; } if (this.activeTab_ == tab.tab) { this.setContent(tab.content); this.updateContent_(); } this.redraw_(); }; InfoBubble.prototype['updateTab'] = InfoBubble.prototype.updateTab; /** * Remove a tab at a specific index * * @param {number} index The index of the tab to remove. */ InfoBubble.prototype.removeTab = function(index) { if (!this.tabs_.length || index < 0 || index >= this.tabs_.length) { return; } var tab = this.tabs_[index]; tab.tab.parentNode.removeChild(tab.tab); google.maps.event.removeListener(tab.tab.listener_); this.tabs_.splice(index, 1); delete tab; for (var i = 0, t; t = this.tabs_[i]; i++) { t.tab.index = i; } if (tab.tab == this.activeTab_) { // Removing the current active tab if (this.tabs_[index]) { // Show the tab to the right this.activeTab_ = this.tabs_[index].tab; } else if (this.tabs_[index - 1]) { // Show a tab to the left this.activeTab_ = this.tabs_[index - 1].tab; } else { // No tabs left to sho this.activeTab_ = undefined; } this.setTabActive_(this.activeTab_); } this.redraw_(); }; InfoBubble.prototype['removeTab'] = InfoBubble.prototype.removeTab; /** * Get the size of an element * @private * @param {Node|string} element The element to size. * @param {number=} opt_maxWidth Optional max width of the element. * @param {number=} opt_maxHeight Optional max height of the element. * @return {google.maps.Size} The size of the element. */ InfoBubble.prototype.getElementSize_ = function(element, opt_maxWidth, opt_maxHeight) { var sizer = document.createElement('DIV'); sizer.style['display'] = 'inline'; sizer.style['position'] = 'absolute'; sizer.style['visibility'] = 'hidden'; if (typeof element == 'string') { sizer.innerHTML = element; } else { sizer.appendChild(element.cloneNode(true)); } document.body.appendChild(sizer); var size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight); // If the width is bigger than the max width then set the width and size again if (opt_maxWidth && size.width > opt_maxWidth) { sizer.style['width'] = this.px(opt_maxWidth); size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight); } // If the height is bigger than the max height then set the height and size // again if (opt_maxHeight && size.height > opt_maxHeight) { sizer.style['height'] = this.px(opt_maxHeight); size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight); } document.body.removeChild(sizer); delete sizer; return size; }; /** * Redraw the InfoBubble * @private */ InfoBubble.prototype.redraw_ = function() { this.figureOutSize_(); this.positionCloseButton_(); this.draw(); }; /** * Figure out the optimum size of the InfoBubble * @private */ InfoBubble.prototype.figureOutSize_ = function() { var map = this.get('map'); if (!map) { return; } var padding = this.getPadding_(); var borderWidth = this.getBorderWidth_(); var borderRadius = this.getBorderRadius_(); var arrowSize = this.getArrowSize_(); var mapDiv = map.getDiv(); var gutter = arrowSize * 2; var mapWidth = mapDiv.offsetWidth - gutter; var mapHeight = mapDiv.offsetHeight - gutter - this.getAnchorHeight_(); var tabHeight = 0; var width = /** @type {number} */ (this.get('minWidth') || 0); var height = /** @type {number} */ (this.get('minHeight') || 0); var maxWidth = /** @type {number} */ (this.get('maxWidth') || 0); var maxHeight = /** @type {number} */ (this.get('maxHeight') || 0); maxWidth = Math.min(mapWidth, maxWidth); maxHeight = Math.min(mapHeight, maxHeight); var tabWidth = 0; if (this.tabs_.length) { // If there are tabs then you need to check the size of each tab's content for (var i = 0, tab; tab = this.tabs_[i]; i++) { var tabSize = this.getElementSize_(tab.tab, maxWidth, maxHeight); var contentSize = this.getElementSize_(tab.content, maxWidth, maxHeight); if (width < tabSize.width) { width = tabSize.width; } // Add up all the tab widths because they might end up being wider than // the content tabWidth += tabSize.width; if (height < tabSize.height) { height = tabSize.height; } if (tabSize.height > tabHeight) { tabHeight = tabSize.height; } if (width < contentSize.width) { width = contentSize.width; } if (height < contentSize.height) { height = contentSize.height; } } } else { var content = /** @type {string|Node} */ (this.get('content')); if (typeof content == 'string') { content = this.htmlToDocumentFragment_(content); } if (content) { var contentSize = this.getElementSize_(content, maxWidth, maxHeight); if (width < contentSize.width) { width = contentSize.width; } if (height < contentSize.height) { height = contentSize.height; } } } if (maxWidth) { width = Math.min(width, maxWidth); } if (maxHeight) { height = Math.min(height, maxHeight); } width = Math.max(width, tabWidth); if (width == tabWidth) { width = width + 2 * padding; } arrowSize = arrowSize * 2; width = Math.max(width, arrowSize); // Maybe add this as a option so they can go bigger than the map if the user // wants if (width > mapWidth) { width = mapWidth; } if (height > mapHeight) { height = mapHeight - tabHeight; } if (this.tabsContainer_) { this.tabHeight_ = tabHeight; this.tabsContainer_.style['width'] = this.px(tabWidth); } this.contentContainer_.style['width'] = this.px(width); this.contentContainer_.style['height'] = this.px(height); }; /** * Get the height of the anchor * * This function is a hack for now and doesn't really work that good, need to * wait for pixelBounds to be correctly exposed. * @private * @return {number} The height of the anchor. */ InfoBubble.prototype.getAnchorHeight_ = function() { var anchor = this.get('anchor'); if (anchor) { var anchorPoint = /** @type google.maps.Point */(this.get('anchorPoint')); if (anchorPoint) { return -1 * anchorPoint.y; } } return 0; }; InfoBubble.prototype.anchorPoint_changed = function() { this.draw(); }; InfoBubble.prototype['anchorPoint_changed'] = InfoBubble.prototype.anchorPoint_changed; /** * Position the close button in the right spot. * @private */ InfoBubble.prototype.positionCloseButton_ = function() { var br = this.getBorderRadius_(); var bw = this.getBorderWidth_(); var right = 2; var top = 2; if (this.tabs_.length && this.tabHeight_) { top += this.tabHeight_; } top += bw; right += bw; var c = this.contentContainer_; if (c && c.clientHeight < c.scrollHeight) { // If there are scrollbars then move the cross in so it is not over // scrollbar right += 15; } this.close_.style['right'] = this.px(right); this.close_.style['top'] = this.px(top); };